提交 4962c547 编写于 作者: R roland

8031752: Failed speculative optimizations should be reattempted when root of...

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: kvn, twisti
上级 672b21b7
...@@ -103,6 +103,7 @@ friend class ciMethodHandle; \ ...@@ -103,6 +103,7 @@ friend class ciMethodHandle; \
friend class ciMethodType; \ friend class ciMethodType; \
friend class ciReceiverTypeData; \ friend class ciReceiverTypeData; \
friend class ciTypeEntries; \ friend class ciTypeEntries; \
friend class ciSpeculativeTrapData; \
friend class ciSymbol; \ friend class ciSymbol; \
friend class ciArray; \ friend class ciArray; \
friend class ciObjArray; \ friend class ciObjArray; \
......
...@@ -78,6 +78,35 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) { ...@@ -78,6 +78,35 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
_parameters = NULL; _parameters = NULL;
} }
void ciMethodData::load_extra_data() {
MethodData* mdo = get_MethodData();
// speculative trap entries also hold a pointer to a Method so need to be translated
DataLayout* dp_src = mdo->extra_data_base();
DataLayout* end_src = mdo->extra_data_limit();
DataLayout* dp_dst = extra_data_base();
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
assert(dp_src < end_src, "moved past end of extra data");
assert(dp_src->tag() == dp_dst->tag(), err_msg("should be same tags %d != %d", dp_src->tag(), dp_dst->tag()));
switch(dp_src->tag()) {
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
data_dst->translate_from(data_src);
break;
}
case DataLayout::bit_data_tag:
break;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
// An empty slot or ArgInfoData entry marks the end of the trap data
return;
default:
fatal(err_msg("bad tag = %d", dp_src->tag()));
}
}
}
void ciMethodData::load_data() { void ciMethodData::load_data() {
MethodData* mdo = get_MethodData(); MethodData* mdo = get_MethodData();
if (mdo == NULL) { if (mdo == NULL) {
...@@ -116,6 +145,8 @@ void ciMethodData::load_data() { ...@@ -116,6 +145,8 @@ void ciMethodData::load_data() {
parameters->translate_from(mdo->parameters_type_data()); parameters->translate_from(mdo->parameters_type_data());
} }
load_extra_data();
// Note: Extra data are all BitData, and do not need translation. // Note: Extra data are all BitData, and do not need translation.
_current_mileage = MethodData::mileage_of(mdo->method()); _current_mileage = MethodData::mileage_of(mdo->method());
_invocation_counter = mdo->invocation_count(); _invocation_counter = mdo->invocation_count();
...@@ -156,6 +187,12 @@ void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) { ...@@ -156,6 +187,12 @@ void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) {
set_type(translate_klass(k)); set_type(translate_klass(k));
} }
void ciSpeculativeTrapData::translate_from(const ProfileData* data) {
Method* m = data->as_SpeculativeTrapData()->method();
ciMethod* ci_m = CURRENT_ENV->get_method(m);
set_method(ci_m);
}
// Get the data at an arbitrary (sort of) data index. // Get the data at an arbitrary (sort of) data index.
ciProfileData* ciMethodData::data_at(int data_index) { ciProfileData* ciMethodData::data_at(int data_index) {
if (out_of_bounds(data_index)) { if (out_of_bounds(data_index)) {
...@@ -203,33 +240,65 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) { ...@@ -203,33 +240,65 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) {
return next; return next;
} }
// Translate a bci to its corresponding data, or NULL. ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
ciProfileData* ciMethodData::bci_to_data(int bci) {
ciProfileData* data = data_before(bci);
for ( ; is_valid(data); data = next_data(data)) {
if (data->bci() == bci) {
set_hint_di(dp_to_di(data->dp()));
return data;
} else if (data->bci() > bci) {
break;
}
}
// bci_to_extra_data(bci) ... // bci_to_extra_data(bci) ...
DataLayout* dp = data_layout_at(data_size()); DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size()); DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (; dp < end; dp = MethodData::next_extra(dp)) { two_free_slots = false;
if (dp->tag() == DataLayout::no_tag) { for (;dp < end; dp = MethodData::next_extra(dp)) {
switch(dp->tag()) {
case DataLayout::no_tag:
_saw_free_extra_data = true; // observed an empty slot (common case) _saw_free_extra_data = true; // observed an empty slot (common case)
two_free_slots = (MethodData::next_extra(dp)->tag() == DataLayout::no_tag);
return NULL; return NULL;
case DataLayout::arg_info_data_tag:
return NULL; // ArgInfoData is at the end of extra data section.
case DataLayout::bit_data_tag:
if (m == NULL && dp->bci() == bci) {
return new ciBitData(dp);
}
break;
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data = new ciSpeculativeTrapData(dp);
// data->method() might be null if the MDO is snapshotted
// concurrently with a trap
if (m != NULL && data->method() == m && dp->bci() == bci) {
return data;
}
break;
} }
if (dp->tag() == DataLayout::arg_info_data_tag) { default:
break; // ArgInfoData is at the end of extra data section. fatal(err_msg("bad tag = %d", dp->tag()));
} }
if (dp->bci() == bci) { }
assert(dp->tag() == DataLayout::bit_data_tag, "sane"); return NULL;
return new ciBitData(dp); }
// Translate a bci to its corresponding data, or NULL.
ciProfileData* ciMethodData::bci_to_data(int bci, ciMethod* m) {
// If m is not NULL we look for a SpeculativeTrapData entry
if (m == NULL) {
ciProfileData* data = data_before(bci);
for ( ; is_valid(data); data = next_data(data)) {
if (data->bci() == bci) {
set_hint_di(dp_to_di(data->dp()));
return data;
} else if (data->bci() > bci) {
break;
}
} }
} }
bool two_free_slots = false;
ciProfileData* result = bci_to_extra_data(bci, m, two_free_slots);
if (result != NULL) {
return result;
}
if (m != NULL && !two_free_slots) {
// We were looking for a SpeculativeTrapData entry we didn't
// find. Room is not available for more SpeculativeTrapData
// entries, look in the non SpeculativeTrapData entries.
return bci_to_data(bci, NULL);
}
return NULL; return NULL;
} }
...@@ -525,18 +594,25 @@ void ciMethodData::print_data_on(outputStream* st) { ...@@ -525,18 +594,25 @@ void ciMethodData::print_data_on(outputStream* st) {
st->print_cr("--- Extra data:"); st->print_cr("--- Extra data:");
DataLayout* dp = data_layout_at(data_size()); DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size()); DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (; dp < end; dp = MethodData::next_extra(dp)) { for (;; dp = MethodData::next_extra(dp)) {
if (dp->tag() == DataLayout::no_tag) continue; assert(dp < end, "moved past end of extra data");
if (dp->tag() == DataLayout::bit_data_tag) { switch (dp->tag()) {
case DataLayout::no_tag:
continue;
case DataLayout::bit_data_tag:
data = new BitData(dp); data = new BitData(dp);
} else { break;
assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo"); case DataLayout::arg_info_data_tag:
data = new ciArgInfoData(dp); data = new ciArgInfoData(dp);
dp = end; // ArgInfoData is at the end of extra data section. dp = end; // ArgInfoData is at the end of extra data section.
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
} }
st->print("%d", dp_to_di(data->dp())); st->print("%d", dp_to_di(data->dp()));
st->fill_to(6); st->fill_to(6);
data->print_data_on(st); data->print_data_on(st);
if (dp >= end) return;
} }
} }
...@@ -569,8 +645,8 @@ void ciReturnTypeEntry::print_data_on(outputStream* st) const { ...@@ -569,8 +645,8 @@ void ciReturnTypeEntry::print_data_on(outputStream* st) const {
st->cr(); st->cr();
} }
void ciCallTypeData::print_data_on(outputStream* st) const { void ciCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciCallTypeData"); print_shared(st, "ciCallTypeData", extra);
if (has_arguments()) { if (has_arguments()) {
tab(st, true); tab(st, true);
st->print("argument types"); st->print("argument types");
...@@ -599,18 +675,18 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const { ...@@ -599,18 +675,18 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
} }
} }
void ciReceiverTypeData::print_data_on(outputStream* st) const { void ciReceiverTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciReceiverTypeData"); print_shared(st, "ciReceiverTypeData", extra);
print_receiver_data_on(st); print_receiver_data_on(st);
} }
void ciVirtualCallData::print_data_on(outputStream* st) const { void ciVirtualCallData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallData"); print_shared(st, "ciVirtualCallData", extra);
rtd_super()->print_receiver_data_on(st); rtd_super()->print_receiver_data_on(st);
} }
void ciVirtualCallTypeData::print_data_on(outputStream* st) const { void ciVirtualCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallTypeData"); print_shared(st, "ciVirtualCallTypeData", extra);
rtd_super()->print_receiver_data_on(st); rtd_super()->print_receiver_data_on(st);
if (has_arguments()) { if (has_arguments()) {
tab(st, true); tab(st, true);
...@@ -624,8 +700,15 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const { ...@@ -624,8 +700,15 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
} }
} }
void ciParametersTypeData::print_data_on(outputStream* st) const { void ciParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("Parametertypes"); st->print_cr("ciParametersTypeData");
parameters()->print_data_on(st); parameters()->print_data_on(st);
} }
void ciSpeculativeTrapData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("ciSpeculativeTrapData");
tab(st);
method()->print_short_name(st);
st->cr();
}
#endif #endif
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "ci/ciUtilities.hpp" #include "ci/ciUtilities.hpp"
#include "oops/methodData.hpp" #include "oops/methodData.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "runtime/deoptimization.hpp"
class ciBitData; class ciBitData;
class ciCounterData; class ciCounterData;
...@@ -44,6 +45,7 @@ class ciArgInfoData; ...@@ -44,6 +45,7 @@ class ciArgInfoData;
class ciCallTypeData; class ciCallTypeData;
class ciVirtualCallTypeData; class ciVirtualCallTypeData;
class ciParametersTypeData; class ciParametersTypeData;
class ciSpeculativeTrapData;;
typedef ProfileData ciProfileData; typedef ProfileData ciProfileData;
...@@ -173,7 +175,7 @@ public: ...@@ -173,7 +175,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra) const;
#endif #endif
}; };
...@@ -200,7 +202,7 @@ public: ...@@ -200,7 +202,7 @@ public:
} }
void translate_receiver_data_from(const ProfileData* data); void translate_receiver_data_from(const ProfileData* data);
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra) const;
void print_receiver_data_on(outputStream* st) const; void print_receiver_data_on(outputStream* st) const;
#endif #endif
}; };
...@@ -225,7 +227,7 @@ public: ...@@ -225,7 +227,7 @@ public:
rtd_super()->translate_receiver_data_from(data); rtd_super()->translate_receiver_data_from(data);
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra) const;
#endif #endif
}; };
...@@ -287,7 +289,7 @@ public: ...@@ -287,7 +289,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra) const;
#endif #endif
}; };
...@@ -336,7 +338,26 @@ public: ...@@ -336,7 +338,26 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciSpeculativeTrapData : public SpeculativeTrapData {
public:
ciSpeculativeTrapData(DataLayout* layout) : SpeculativeTrapData(layout) {}
virtual void translate_from(const ProfileData* data);
ciMethod* method() const {
return (ciMethod*)intptr_at(method_offset);
}
void set_method(ciMethod* m) {
set_intptr_at(method_offset, (intptr_t)m);
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif #endif
}; };
...@@ -436,6 +457,16 @@ private: ...@@ -436,6 +457,16 @@ private:
ciArgInfoData *arg_info() const; ciArgInfoData *arg_info() const;
address data_base() const {
return (address) _data;
}
DataLayout* limit_data_position() const {
return (DataLayout*)((address)data_base() + _data_size);
}
void load_extra_data();
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
public: public:
bool is_method_data() const { return true; } bool is_method_data() const { return true; }
...@@ -475,9 +506,11 @@ public: ...@@ -475,9 +506,11 @@ public:
ciProfileData* next_data(ciProfileData* current); ciProfileData* next_data(ciProfileData* current);
bool is_valid(ciProfileData* current) { return current != NULL; } bool is_valid(ciProfileData* current) { return current != NULL; }
// Get the data at an arbitrary bci, or NULL if there is none. DataLayout* extra_data_base() const { return limit_data_position(); }
ciProfileData* bci_to_data(int bci);
ciProfileData* bci_to_extra_data(int bci, bool create_if_missing); // Get the data at an arbitrary bci, or NULL if there is none. If m
// is not NULL look for a SpeculativeTrapData if any first.
ciProfileData* bci_to_data(int bci, ciMethod* m = NULL);
uint overflow_trap_count() const { uint overflow_trap_count() const {
return _orig.overflow_trap_count(); return _orig.overflow_trap_count();
...@@ -496,12 +529,13 @@ public: ...@@ -496,12 +529,13 @@ public:
// Helpful query functions that decode trap_state. // Helpful query functions that decode trap_state.
int has_trap_at(ciProfileData* data, int reason); int has_trap_at(ciProfileData* data, int reason);
int has_trap_at(int bci, int reason) { int has_trap_at(int bci, ciMethod* m, int reason) {
return has_trap_at(bci_to_data(bci), reason); assert((m != NULL) == Deoptimization::reason_is_speculate(reason), "inconsistent method/reason");
return has_trap_at(bci_to_data(bci, m), reason);
} }
int trap_recompiled_at(ciProfileData* data); int trap_recompiled_at(ciProfileData* data);
int trap_recompiled_at(int bci) { int trap_recompiled_at(int bci, ciMethod* m) {
return trap_recompiled_at(bci_to_data(bci)); return trap_recompiled_at(bci_to_data(bci, m));
} }
void clear_escape_info(); void clear_escape_info();
......
...@@ -596,7 +596,7 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) { ...@@ -596,7 +596,7 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) {
if (data != NULL) { if (data != NULL) {
st->print(" %d", mdo->dp_to_di(data->dp())); st->print(" %d", mdo->dp_to_di(data->dp()));
st->fill_to(6); st->fill_to(6);
data->print_data_on(st); data->print_data_on(st, mdo);
} }
} }
} }
......
...@@ -2192,15 +2192,7 @@ void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) { ...@@ -2192,15 +2192,7 @@ void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) {
for (int m = 0; m < methods()->length(); m++) { for (int m = 0; m < methods()->length(); m++) {
MethodData* mdo = methods()->at(m)->method_data(); MethodData* mdo = methods()->at(m)->method_data();
if (mdo != NULL) { if (mdo != NULL) {
for (ProfileData* data = mdo->first_data(); mdo->clean_method_data(is_alive);
mdo->is_valid(data);
data = mdo->next_data(data)) {
data->clean_weak_klass_links(is_alive);
}
ParametersTypeData* parameters = mdo->parameters_type_data();
if (parameters != NULL) {
parameters->clean_weak_klass_links(is_alive);
}
} }
} }
} }
......
...@@ -306,7 +306,7 @@ class InstanceKlass: public Klass { ...@@ -306,7 +306,7 @@ class InstanceKlass: public Klass {
// three cases: // three cases:
// NULL: no implementor. // NULL: no implementor.
// A Klass* that's not itself: one implementor. // A Klass* that's not itself: one implementor.
// Itsef: more than one implementors. // Itself: more than one implementors.
// embedded host klass follows here // embedded host klass follows here
// The embedded host klass only exists in an anonymous class for // The embedded host klass only exists in an anonymous class for
// dynamic language support (JSR 292 enabled). The host class grants // dynamic language support (JSR 292 enabled). The host class grants
......
...@@ -120,7 +120,8 @@ public: ...@@ -120,7 +120,8 @@ public:
arg_info_data_tag, arg_info_data_tag,
call_type_data_tag, call_type_data_tag,
virtual_call_type_data_tag, virtual_call_type_data_tag,
parameters_type_data_tag parameters_type_data_tag,
speculative_trap_data_tag
}; };
enum { enum {
...@@ -189,8 +190,11 @@ public: ...@@ -189,8 +190,11 @@ public:
void set_header(intptr_t value) { void set_header(intptr_t value) {
_header._bits = value; _header._bits = value;
} }
void release_set_header(intptr_t value) { bool atomic_set_header(intptr_t value) {
OrderAccess::release_store_ptr(&_header._bits, value); if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) {
return true;
}
return false;
} }
intptr_t header() { intptr_t header() {
return _header._bits; return _header._bits;
...@@ -271,6 +275,7 @@ class ArrayData; ...@@ -271,6 +275,7 @@ class ArrayData;
class MultiBranchData; class MultiBranchData;
class ArgInfoData; class ArgInfoData;
class ParametersTypeData; class ParametersTypeData;
class SpeculativeTrapData;
// ProfileData // ProfileData
// //
...@@ -291,6 +296,8 @@ private: ...@@ -291,6 +296,8 @@ private:
// This is a pointer to a section of profiling data. // This is a pointer to a section of profiling data.
DataLayout* _data; DataLayout* _data;
char* print_data_on_helper(const MethodData* md) const;
protected: protected:
DataLayout* data() { return _data; } DataLayout* data() { return _data; }
const DataLayout* data() const { return _data; } const DataLayout* data() const { return _data; }
...@@ -440,6 +447,7 @@ public: ...@@ -440,6 +447,7 @@ public:
virtual bool is_CallTypeData() const { return false; } virtual bool is_CallTypeData() const { return false; }
virtual bool is_VirtualCallTypeData()const { return false; } virtual bool is_VirtualCallTypeData()const { return false; }
virtual bool is_ParametersTypeData() const { return false; } virtual bool is_ParametersTypeData() const { return false; }
virtual bool is_SpeculativeTrapData()const { return false; }
BitData* as_BitData() const { BitData* as_BitData() const {
...@@ -494,6 +502,10 @@ public: ...@@ -494,6 +502,10 @@ public:
assert(is_ParametersTypeData(), "wrong type"); assert(is_ParametersTypeData(), "wrong type");
return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL; return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
} }
SpeculativeTrapData* as_SpeculativeTrapData() const {
assert(is_SpeculativeTrapData(), "wrong type");
return is_SpeculativeTrapData() ? (SpeculativeTrapData*)this : NULL;
}
// Subclass specific initialization // Subclass specific initialization
...@@ -509,12 +521,14 @@ public: ...@@ -509,12 +521,14 @@ public:
// translation here, and the required translators are in the ci subclasses. // translation here, and the required translators are in the ci subclasses.
virtual void translate_from(const ProfileData* data) {} 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(); ShouldNotReachHere();
} }
void print_data_on(outputStream* st, const MethodData* md) const;
#ifndef PRODUCT #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; void tab(outputStream* st, bool first = false) const;
#endif #endif
}; };
...@@ -576,7 +590,7 @@ public: ...@@ -576,7 +590,7 @@ public:
#endif // CC_INTERP #endif // CC_INTERP
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -639,7 +653,7 @@ public: ...@@ -639,7 +653,7 @@ public:
#endif // CC_INTERP #endif // CC_INTERP
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -726,7 +740,7 @@ public: ...@@ -726,7 +740,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo); void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1137,7 +1151,7 @@ public: ...@@ -1137,7 +1151,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
virtual void print_data_on(outputStream* st) const; virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1282,7 +1296,7 @@ public: ...@@ -1282,7 +1296,7 @@ public:
#ifndef PRODUCT #ifndef PRODUCT
void print_receiver_data_on(outputStream* st) const; 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 #endif
}; };
...@@ -1325,7 +1339,7 @@ public: ...@@ -1325,7 +1339,7 @@ public:
#endif // CC_INTERP #endif // CC_INTERP
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1451,7 +1465,7 @@ public: ...@@ -1451,7 +1465,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
virtual void print_data_on(outputStream* st) const; virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1554,7 +1568,7 @@ public: ...@@ -1554,7 +1568,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo); void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1632,7 +1646,7 @@ public: ...@@ -1632,7 +1646,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo); void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1825,7 +1839,7 @@ public: ...@@ -1825,7 +1839,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo); void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1852,7 +1866,7 @@ public: ...@@ -1852,7 +1866,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
void print_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
}; };
...@@ -1913,7 +1927,7 @@ public: ...@@ -1913,7 +1927,7 @@ public:
} }
#ifndef PRODUCT #ifndef PRODUCT
virtual void print_data_on(outputStream* st) const; virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif #endif
static ByteSize stack_slot_offset(int i) { static ByteSize stack_slot_offset(int i) {
...@@ -1925,6 +1939,54 @@ public: ...@@ -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* // MethodData*
// //
// A MethodData* holds information which has been collected about // A MethodData* holds information which has been collected about
...@@ -1994,7 +2056,7 @@ public: ...@@ -1994,7 +2056,7 @@ public:
// Whole-method sticky bits and flags // Whole-method sticky bits and flags
enum { enum {
_trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_mask = max_jubyte, _trap_hist_mask = max_jubyte,
_extra_data_count = 4 // extra DataLayout headers, for trap history _extra_data_count = 4 // extra DataLayout headers, for trap history
}; // Public flag values }; // Public flag values
...@@ -2049,6 +2111,7 @@ private: ...@@ -2049,6 +2111,7 @@ private:
// Helper for size computation // Helper for size computation
static int compute_data_size(BytecodeStream* stream); static int compute_data_size(BytecodeStream* stream);
static int bytecode_cell_count(Bytecodes::Code code); 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 }; enum { no_profile_data = -1, variable_cell_count = -2 };
// Helper for initialization // Helper for initialization
...@@ -2092,8 +2155,9 @@ private: ...@@ -2092,8 +2155,9 @@ private:
// What is the index of the first data entry? // What is the index of the first data entry?
int first_di() const { return 0; } int first_di() const { return 0; }
ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp);
// Find or create an extra ProfileData: // 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 // return the argument info cell
ArgInfoData *arg_info(); ArgInfoData *arg_info();
...@@ -2116,6 +2180,10 @@ private: ...@@ -2116,6 +2180,10 @@ private:
static bool profile_parameters_jsr292_only(); static bool profile_parameters_jsr292_only();
static bool profile_all_parameters(); 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: public:
static int header_size() { static int header_size() {
return sizeof(MethodData)/wordSize; return sizeof(MethodData)/wordSize;
...@@ -2124,7 +2192,7 @@ public: ...@@ -2124,7 +2192,7 @@ public:
// Compute the size of a MethodData* before it is created. // 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_bytes(methodHandle method);
static int compute_allocation_size_in_words(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. // Determine if a given bytecode can have profile information.
static bool bytecode_has_profile(Bytecodes::Code code) { static bool bytecode_has_profile(Bytecodes::Code code) {
...@@ -2265,9 +2333,26 @@ public: ...@@ -2265,9 +2333,26 @@ public:
ProfileData* bci_to_data(int bci); ProfileData* bci_to_data(int bci);
// Same, but try to create an extra_data record if one is needed: // Same, but try to create an extra_data record if one is needed:
ProfileData* allocate_bci_to_data(int bci) { ProfileData* allocate_bci_to_data(int bci, Method* m) {
ProfileData* data = bci_to_data(bci); ProfileData* data = NULL;
return (data != NULL) ? data : bci_to_extra_data(bci, true); // 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. // Add a handful of extra data records, for trap tracking.
...@@ -2275,7 +2360,7 @@ public: ...@@ -2275,7 +2360,7 @@ public:
DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); } DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); }
int extra_data_size() const { return (address)extra_data_limit() int extra_data_size() const { return (address)extra_data_limit()
- (address)extra_data_base(); } - (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. // Return (uint)-1 for overflow.
uint trap_count(int reason) const { uint trap_count(int reason) const {
...@@ -2375,6 +2460,8 @@ public: ...@@ -2375,6 +2460,8 @@ public:
static bool profile_return(); static bool profile_return();
static bool profile_parameters(); static bool profile_parameters();
static bool profile_return_jsr292_only(); static bool profile_return_jsr292_only();
void clean_method_data(BoolObjectClosure* is_alive);
}; };
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
...@@ -3249,7 +3249,8 @@ bool Compile::too_many_traps(ciMethod* method, ...@@ -3249,7 +3249,8 @@ bool Compile::too_many_traps(ciMethod* method,
// because of a transient condition during start-up in the interpreter. // because of a transient condition during start-up in the interpreter.
return false; return false;
} }
if (md->has_trap_at(bci, reason) != 0) { ciMethod* m = Deoptimization::reason_is_speculate(reason) ? this->method() : NULL;
if (md->has_trap_at(bci, m, reason) != 0) {
// Assume PerBytecodeTrapLimit==0, for a more conservative heuristic. // Assume PerBytecodeTrapLimit==0, for a more conservative heuristic.
// Also, if there are multiple reasons, or if there is no per-BCI record, // Also, if there are multiple reasons, or if there is no per-BCI record,
// assume the worst. // assume the worst.
...@@ -3267,7 +3268,7 @@ bool Compile::too_many_traps(ciMethod* method, ...@@ -3267,7 +3268,7 @@ bool Compile::too_many_traps(ciMethod* method,
// Less-accurate variant which does not require a method and bci. // Less-accurate variant which does not require a method and bci.
bool Compile::too_many_traps(Deoptimization::DeoptReason reason, bool Compile::too_many_traps(Deoptimization::DeoptReason reason,
ciMethodData* logmd) { ciMethodData* logmd) {
if (trap_count(reason) >= (uint)PerMethodTrapLimit) { if (trap_count(reason) >= Deoptimization::per_method_trap_limit(reason)) {
// Too many traps globally. // Too many traps globally.
// Note that we use cumulative trap_count, not just md->trap_count. // Note that we use cumulative trap_count, not just md->trap_count.
if (log()) { if (log()) {
...@@ -3302,10 +3303,11 @@ bool Compile::too_many_recompiles(ciMethod* method, ...@@ -3302,10 +3303,11 @@ bool Compile::too_many_recompiles(ciMethod* method,
uint m_cutoff = (uint) PerMethodRecompilationCutoff / 2 + 1; // not zero uint m_cutoff = (uint) PerMethodRecompilationCutoff / 2 + 1; // not zero
Deoptimization::DeoptReason per_bc_reason Deoptimization::DeoptReason per_bc_reason
= Deoptimization::reason_recorded_per_bytecode_if_any(reason); = Deoptimization::reason_recorded_per_bytecode_if_any(reason);
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? this->method() : NULL;
if ((per_bc_reason == Deoptimization::Reason_none if ((per_bc_reason == Deoptimization::Reason_none
|| md->has_trap_at(bci, reason) != 0) || md->has_trap_at(bci, m, reason) != 0)
// The trap frequency measure we care about is the recompile count: // The trap frequency measure we care about is the recompile count:
&& md->trap_recompiled_at(bci) && md->trap_recompiled_at(bci, m)
&& md->overflow_recompile_count() >= bc_cutoff) { && md->overflow_recompile_count() >= bc_cutoff) {
// Do not emit a trap here if it has already caused recompilations. // Do not emit a trap here if it has already caused recompilations.
// Also, if there are multiple reasons, or if there is no per-BCI record, // Also, if there are multiple reasons, or if there is no per-BCI record,
......
...@@ -250,7 +250,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool ...@@ -250,7 +250,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
CallGenerator* miss_cg; CallGenerator* miss_cg;
Deoptimization::DeoptReason reason = morphism == 2 ? Deoptimization::DeoptReason reason = morphism == 2 ?
Deoptimization::Reason_bimorphic : Deoptimization::Reason_bimorphic :
Deoptimization::Reason_class_check; (speculative_receiver_type == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check);
if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) && if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) &&
!too_many_traps(jvms->method(), jvms->bci(), reason) !too_many_traps(jvms->method(), jvms->bci(), reason)
) { ) {
......
...@@ -612,9 +612,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) { ...@@ -612,9 +612,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
// Usual case: Bail to interpreter. // Usual case: Bail to interpreter.
// Reserve the right to recompile if we haven't seen anything yet. // Reserve the right to recompile if we haven't seen anything yet.
assert(!Deoptimization::reason_is_speculate(reason), "unsupported");
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile; Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
if (treat_throw_as_hot if (treat_throw_as_hot
&& (method()->method_data()->trap_recompiled_at(bci()) && (method()->method_data()->trap_recompiled_at(bci(), NULL)
|| C->too_many_traps(reason))) { || C->too_many_traps(reason))) {
// We cannot afford to take more traps here. Suffer in the interpreter. // We cannot afford to take more traps here. Suffer in the interpreter.
if (C->log() != NULL) if (C->log() != NULL)
...@@ -2145,7 +2146,7 @@ Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) { ...@@ -2145,7 +2146,7 @@ Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
* *
* @param n receiver node * @param n receiver node
* *
* @return node with improved type * @return node with improved type
*/ */
Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) { Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
if (!UseTypeSpeculation) { if (!UseTypeSpeculation) {
...@@ -2739,12 +2740,14 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { ...@@ -2739,12 +2740,14 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
// Subsequent type checks will always fold up. // Subsequent type checks will always fold up.
Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* require_klass, ciKlass* require_klass,
ciKlass* spec_klass, ciKlass* spec_klass,
bool safe_for_replace) { bool safe_for_replace) {
if (!UseTypeProfile || !TypeProfileCasts) return NULL; if (!UseTypeProfile || !TypeProfileCasts) return NULL;
Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check;
// Make sure we haven't already deoptimized from this tactic. // Make sure we haven't already deoptimized from this tactic.
if (too_many_traps(Deoptimization::Reason_class_check)) if (too_many_traps(reason))
return NULL; return NULL;
// (No, this isn't a call, but it's enough like a virtual call // (No, this isn't a call, but it's enough like a virtual call
...@@ -2766,7 +2769,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, ...@@ -2766,7 +2769,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
&exact_obj); &exact_obj);
{ PreserveJVMState pjvms(this); { PreserveJVMState pjvms(this);
set_control(slow_ctl); set_control(slow_ctl);
uncommon_trap(Deoptimization::Reason_class_check, uncommon_trap(reason,
Deoptimization::Action_maybe_recompile); Deoptimization::Action_maybe_recompile);
} }
if (safe_for_replace) { if (safe_for_replace) {
...@@ -2793,8 +2796,10 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, ...@@ -2793,8 +2796,10 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
bool not_null) { bool not_null) {
// type == NULL if profiling tells us this object is always null // type == NULL if profiling tells us this object is always null
if (type != NULL) { if (type != NULL) {
if (!too_many_traps(Deoptimization::Reason_null_check) && Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
!too_many_traps(Deoptimization::Reason_class_check)) { Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check;
if (!too_many_traps(null_reason) &&
!too_many_traps(class_reason)) {
Node* not_null_obj = NULL; Node* not_null_obj = NULL;
// not_null is true if we know the object is not null and // not_null is true if we know the object is not null and
// there's no need for a null check // there's no need for a null check
...@@ -2813,7 +2818,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, ...@@ -2813,7 +2818,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
{ {
PreserveJVMState pjvms(this); PreserveJVMState pjvms(this);
set_control(slow_ctl); set_control(slow_ctl);
uncommon_trap(Deoptimization::Reason_class_check, uncommon_trap(class_reason,
Deoptimization::Action_maybe_recompile); Deoptimization::Action_maybe_recompile);
} }
replace_in_map(not_null_obj, exact_obj); replace_in_map(not_null_obj, exact_obj);
...@@ -2882,7 +2887,7 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac ...@@ -2882,7 +2887,7 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
} }
if (known_statically && UseTypeSpeculation) { if (known_statically && UseTypeSpeculation) {
// If we know the type check always succeed then we don't use the // If we know the type check always succeeds then we don't use the
// profiling data at this bytecode. Don't lose it, feed it to the // profiling data at this bytecode. Don't lose it, feed it to the
// type system as a speculative type. // type system as a speculative type.
not_null_obj = record_profiled_receiver_for_speculation(not_null_obj); not_null_obj = record_profiled_receiver_for_speculation(not_null_obj);
......
...@@ -406,7 +406,7 @@ class GraphKit : public Phase { ...@@ -406,7 +406,7 @@ class GraphKit : public Phase {
// Use the type profile to narrow an object type. // Use the type profile to narrow an object type.
Node* maybe_cast_profiled_receiver(Node* not_null_obj, Node* maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* require_klass, ciKlass* require_klass,
ciKlass* spec, ciKlass* spec,
bool safe_for_replace); bool safe_for_replace);
// Cast obj to type and emit guard unless we had too many traps here already // Cast obj to type and emit guard unless we had too many traps here already
......
...@@ -1489,6 +1489,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra ...@@ -1489,6 +1489,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
bool maybe_prior_trap = false; bool maybe_prior_trap = false;
bool maybe_prior_recompile = false; bool maybe_prior_recompile = false;
pdata = query_update_method_data(trap_mdo, trap_bci, reason, pdata = query_update_method_data(trap_mdo, trap_bci, reason,
nm->method(),
//outputs: //outputs:
this_trap_count, this_trap_count,
maybe_prior_trap, maybe_prior_trap,
...@@ -1534,7 +1535,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra ...@@ -1534,7 +1535,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
} }
// Go back to the compiler if there are too many traps in this method. // Go back to the compiler if there are too many traps in this method.
if (this_trap_count >= (uint)PerMethodTrapLimit) { if (this_trap_count >= per_method_trap_limit(reason)) {
// If there are too many traps in this method, force a recompile. // If there are too many traps in this method, force a recompile.
// This will allow the compiler to see the limit overflow, and // This will allow the compiler to see the limit overflow, and
// take corrective action, if possible. // take corrective action, if possible.
...@@ -1622,6 +1623,7 @@ ProfileData* ...@@ -1622,6 +1623,7 @@ ProfileData*
Deoptimization::query_update_method_data(MethodData* trap_mdo, Deoptimization::query_update_method_data(MethodData* trap_mdo,
int trap_bci, int trap_bci,
Deoptimization::DeoptReason reason, Deoptimization::DeoptReason reason,
Method* compiled_method,
//outputs: //outputs:
uint& ret_this_trap_count, uint& ret_this_trap_count,
bool& ret_maybe_prior_trap, bool& ret_maybe_prior_trap,
...@@ -1645,9 +1647,16 @@ Deoptimization::query_update_method_data(MethodData* trap_mdo, ...@@ -1645,9 +1647,16 @@ Deoptimization::query_update_method_data(MethodData* trap_mdo,
// Find the profile data for this BCI. If there isn't one, // Find the profile data for this BCI. If there isn't one,
// try to allocate one from the MDO's set of spares. // try to allocate one from the MDO's set of spares.
// This will let us detect a repeated trap at this point. // This will let us detect a repeated trap at this point.
pdata = trap_mdo->allocate_bci_to_data(trap_bci); pdata = trap_mdo->allocate_bci_to_data(trap_bci, reason_is_speculate(reason) ? compiled_method : NULL);
if (pdata != NULL) { if (pdata != NULL) {
if (reason_is_speculate(reason) && !pdata->is_SpeculativeTrapData()) {
if (LogCompilation && xtty != NULL) {
ttyLocker ttyl;
// no more room for speculative traps in this MDO
xtty->elem("speculative_traps_oom");
}
}
// Query the trap state of this profile datum. // Query the trap state of this profile datum.
int tstate0 = pdata->trap_state(); int tstate0 = pdata->trap_state();
if (!trap_state_has_reason(tstate0, per_bc_reason)) if (!trap_state_has_reason(tstate0, per_bc_reason))
...@@ -1685,8 +1694,10 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr ...@@ -1685,8 +1694,10 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr
uint ignore_this_trap_count; uint ignore_this_trap_count;
bool ignore_maybe_prior_trap; bool ignore_maybe_prior_trap;
bool ignore_maybe_prior_recompile; bool ignore_maybe_prior_recompile;
assert(!reason_is_speculate(reason), "reason speculate only used by compiler");
query_update_method_data(trap_mdo, trap_bci, query_update_method_data(trap_mdo, trap_bci,
(DeoptReason)reason, (DeoptReason)reason,
NULL,
ignore_this_trap_count, ignore_this_trap_count,
ignore_maybe_prior_trap, ignore_maybe_prior_trap,
ignore_maybe_prior_recompile); ignore_maybe_prior_recompile);
...@@ -1814,7 +1825,8 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = { ...@@ -1814,7 +1825,8 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = {
"div0_check", "div0_check",
"age", "age",
"predicate", "predicate",
"loop_limit_check" "loop_limit_check",
"speculate_class_check"
}; };
const char* Deoptimization::_trap_action_name[Action_LIMIT] = { const char* Deoptimization::_trap_action_name[Action_LIMIT] = {
// Note: Keep this in sync. with enum DeoptAction. // Note: Keep this in sync. with enum DeoptAction.
......
...@@ -59,6 +59,7 @@ class Deoptimization : AllStatic { ...@@ -59,6 +59,7 @@ class Deoptimization : AllStatic {
Reason_age, // nmethod too old; tier threshold reached Reason_age, // nmethod too old; tier threshold reached
Reason_predicate, // compiler generated predicate failed Reason_predicate, // compiler generated predicate failed
Reason_loop_limit_check, // compiler generated loop limits check failed Reason_loop_limit_check, // compiler generated loop limits check failed
Reason_speculate_class_check, // saw unexpected object class from type speculation
Reason_LIMIT, Reason_LIMIT,
// Note: Keep this enum in sync. with _trap_reason_name. // Note: Keep this enum in sync. with _trap_reason_name.
Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc
...@@ -311,10 +312,23 @@ class Deoptimization : AllStatic { ...@@ -311,10 +312,23 @@ class Deoptimization : AllStatic {
return reason; return reason;
else if (reason == Reason_div0_check) // null check due to divide-by-zero? else if (reason == Reason_div0_check) // null check due to divide-by-zero?
return Reason_null_check; // recorded per BCI as a null check return Reason_null_check; // recorded per BCI as a null check
else if (reason == Reason_speculate_class_check)
return Reason_class_check;
else else
return Reason_none; return Reason_none;
} }
static bool reason_is_speculate(int reason) {
if (reason == Reason_speculate_class_check) {
return true;
}
return false;
}
static uint per_method_trap_limit(int reason) {
return reason_is_speculate(reason) ? (uint)PerMethodSpecTrapLimit : (uint)PerMethodTrapLimit;
}
static const char* trap_reason_name(int reason); static const char* trap_reason_name(int reason);
static const char* trap_action_name(int action); static const char* trap_action_name(int action);
// Format like reason='foo' action='bar' index='123'. // Format like reason='foo' action='bar' index='123'.
...@@ -337,6 +351,7 @@ class Deoptimization : AllStatic { ...@@ -337,6 +351,7 @@ class Deoptimization : AllStatic {
static ProfileData* query_update_method_data(MethodData* trap_mdo, static ProfileData* query_update_method_data(MethodData* trap_mdo,
int trap_bci, int trap_bci,
DeoptReason reason, DeoptReason reason,
Method* compiled_method,
//outputs: //outputs:
uint& ret_this_trap_count, uint& ret_this_trap_count,
bool& ret_maybe_prior_trap, bool& ret_maybe_prior_trap,
......
...@@ -3078,9 +3078,15 @@ class CommandLineFlags { ...@@ -3078,9 +3078,15 @@ class CommandLineFlags {
product(intx, PerMethodTrapLimit, 100, \ product(intx, PerMethodTrapLimit, 100, \
"Limit on traps (of one kind) in a method (includes inlines)") \ "Limit on traps (of one kind) in a method (includes inlines)") \
\ \
experimental(intx, PerMethodSpecTrapLimit, 5000, \
"Limit on speculative traps (of one kind) in a method (includes inlines)") \
\
product(intx, PerBytecodeTrapLimit, 4, \ product(intx, PerBytecodeTrapLimit, 4, \
"Limit on traps (of one kind) at a particular BCI") \ "Limit on traps (of one kind) at a particular BCI") \
\ \
experimental(intx, SpecTrapLimitExtraEntries, 3, \
"Extra method data trap entries for speculation") \
\
develop(intx, InlineFrequencyRatio, 20, \ develop(intx, InlineFrequencyRatio, 20, \
"Ratio of call site execution to caller method invocation") \ "Ratio of call site execution to caller method invocation") \
\ \
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8031752
* @summary speculative traps need to be cleaned up at GC
* @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
*
*/
import java.lang.reflect.Method;
public class TestSpecTrapClassUnloading {
static class B {
final public boolean m(Object o) {
if (o.getClass() == B.class) {
return true;
}
return false;
}
}
static class MemoryChunk {
MemoryChunk other;
long[] array;
MemoryChunk(MemoryChunk other) {
other = other;
array = new long[1024 * 1024 * 1024];
}
}
static void m1(B b, Object o) {
b.m(o);
}
static void m2(B b, Object o) {
b.m(o);
}
public static void main(String[] args) throws Exception {
Method m = B.class.getMethod("m", Object.class);
Object o = new Object();
B b = new B();
// add speculative trap in B.m() for m1
for (int i = 0; i < 20000; i++) {
m1(b, b);
}
m1(b, o);
// add speculative trap in B.m() for code generated by reflection
for (int i = 0; i < 20000; i++) {
m.invoke(b, b);
}
m.invoke(b, o);
m = null;
// add speculative trap in B.m() for m2
for (int i = 0; i < 20000; i++) {
m2(b, b);
}
m2(b, o);
// Exhaust memory which causes the code generated by
// reflection to be unloaded but B.m() is not.
MemoryChunk root = null;
try {
while (true) {
root = new MemoryChunk(root);
}
} catch(OutOfMemoryError e) {
root = null;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册