mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
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:
parent
532b570e81
commit
493557fc90
16 changed files with 772 additions and 164 deletions
|
@ -80,8 +80,42 @@ ProfileData::ProfileData() {
|
|||
_data = NULL;
|
||||
}
|
||||
|
||||
char* ProfileData::print_data_on_helper(const MethodData* md) const {
|
||||
DataLayout* dp = md->extra_data_base();
|
||||
DataLayout* end = md->extra_data_limit();
|
||||
stringStream ss;
|
||||
for (;; dp = MethodData::next_extra(dp)) {
|
||||
assert(dp < end, "moved past end of extra data");
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::speculative_trap_data_tag:
|
||||
if (dp->bci() == bci()) {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
int trap = data->trap_state();
|
||||
char buf[100];
|
||||
ss.print("trap/");
|
||||
data->method()->print_short_name(&ss);
|
||||
ss.print("(%s) ", Deoptimization::format_trap_state(buf, sizeof(buf), trap));
|
||||
}
|
||||
break;
|
||||
case DataLayout::bit_data_tag:
|
||||
break;
|
||||
case DataLayout::no_tag:
|
||||
case DataLayout::arg_info_data_tag:
|
||||
return ss.as_string();
|
||||
break;
|
||||
default:
|
||||
fatal(err_msg("unexpected tag %d", dp->tag()));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ProfileData::print_data_on(outputStream* st, const MethodData* md) const {
|
||||
print_data_on(st, print_data_on_helper(md));
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void ProfileData::print_shared(outputStream* st, const char* name) const {
|
||||
void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const {
|
||||
st->print("bci: %d", bci());
|
||||
st->fill_to(tab_width_one);
|
||||
st->print("%s", name);
|
||||
|
@ -91,9 +125,13 @@ void ProfileData::print_shared(outputStream* st, const char* name) const {
|
|||
char buf[100];
|
||||
st->print("trap(%s) ", Deoptimization::format_trap_state(buf, sizeof(buf), trap));
|
||||
}
|
||||
if (extra != NULL) {
|
||||
st->print(extra);
|
||||
}
|
||||
int flags = data()->flags();
|
||||
if (flags != 0)
|
||||
if (flags != 0) {
|
||||
st->print("flags(%d) ", flags);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileData::tab(outputStream* st, bool first) const {
|
||||
|
@ -109,8 +147,8 @@ void ProfileData::tab(outputStream* st, bool first) const {
|
|||
|
||||
|
||||
#ifndef PRODUCT
|
||||
void BitData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "BitData");
|
||||
void BitData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "BitData", extra);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
|
@ -120,8 +158,8 @@ void BitData::print_data_on(outputStream* st) const {
|
|||
// A CounterData corresponds to a simple counter.
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CounterData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "CounterData");
|
||||
void CounterData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "CounterData", extra);
|
||||
st->print_cr("count(%u)", count());
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
@ -150,8 +188,8 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void JumpData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "JumpData");
|
||||
void JumpData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "JumpData", extra);
|
||||
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
@ -332,8 +370,8 @@ void ReturnTypeEntry::print_data_on(outputStream* st) const {
|
|||
st->cr();
|
||||
}
|
||||
|
||||
void CallTypeData::print_data_on(outputStream* st) const {
|
||||
CounterData::print_data_on(st);
|
||||
void CallTypeData::print_data_on(outputStream* st, const char* extra) const {
|
||||
CounterData::print_data_on(st, extra);
|
||||
if (has_arguments()) {
|
||||
tab(st, true);
|
||||
st->print("argument types");
|
||||
|
@ -346,8 +384,8 @@ void CallTypeData::print_data_on(outputStream* st) const {
|
|||
}
|
||||
}
|
||||
|
||||
void VirtualCallTypeData::print_data_on(outputStream* st) const {
|
||||
VirtualCallData::print_data_on(st);
|
||||
void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) const {
|
||||
VirtualCallData::print_data_on(st, extra);
|
||||
if (has_arguments()) {
|
||||
tab(st, true);
|
||||
st->print("argument types");
|
||||
|
@ -400,12 +438,12 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
void ReceiverTypeData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "ReceiverTypeData");
|
||||
void ReceiverTypeData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "ReceiverTypeData", extra);
|
||||
print_receiver_data_on(st);
|
||||
}
|
||||
void VirtualCallData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "VirtualCallData");
|
||||
void VirtualCallData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "VirtualCallData", extra);
|
||||
print_receiver_data_on(st);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
@ -461,8 +499,8 @@ DataLayout* RetData::advance(MethodData *md, int bci) {
|
|||
#endif // CC_INTERP
|
||||
|
||||
#ifndef PRODUCT
|
||||
void RetData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "RetData");
|
||||
void RetData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "RetData", extra);
|
||||
uint row;
|
||||
int entries = 0;
|
||||
for (row = 0; row < row_limit(); row++) {
|
||||
|
@ -496,8 +534,8 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void BranchData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "BranchData");
|
||||
void BranchData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "BranchData", extra);
|
||||
st->print_cr("taken(%u) displacement(%d)",
|
||||
taken(), displacement());
|
||||
tab(st);
|
||||
|
@ -570,8 +608,8 @@ void MultiBranchData::post_initialize(BytecodeStream* stream,
|
|||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void MultiBranchData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "MultiBranchData");
|
||||
void MultiBranchData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "MultiBranchData", extra);
|
||||
st->print_cr("default_count(%u) displacement(%d)",
|
||||
default_count(), default_displacement());
|
||||
int cases = number_of_cases();
|
||||
|
@ -584,8 +622,8 @@ void MultiBranchData::print_data_on(outputStream* st) const {
|
|||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
void ArgInfoData::print_data_on(outputStream* st) const {
|
||||
print_shared(st, "ArgInfoData");
|
||||
void ArgInfoData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "ArgInfoData", extra);
|
||||
int nargs = number_of_args();
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
st->print(" 0x%x", arg_modified(i));
|
||||
|
@ -616,10 +654,17 @@ bool ParametersTypeData::profiling_enabled() {
|
|||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void ParametersTypeData::print_data_on(outputStream* st) const {
|
||||
st->print("parameter types");
|
||||
void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
|
||||
st->print("parameter types", extra);
|
||||
_parameters.print_data_on(st);
|
||||
}
|
||||
|
||||
void SpeculativeTrapData::print_data_on(outputStream* st, const char* extra) const {
|
||||
print_shared(st, "SpeculativeTrapData", extra);
|
||||
tab(st);
|
||||
method()->print_short_name(st);
|
||||
st->cr();
|
||||
}
|
||||
#endif
|
||||
|
||||
// ==================================================================
|
||||
|
@ -745,7 +790,27 @@ int MethodData::compute_data_size(BytecodeStream* stream) {
|
|||
return DataLayout::compute_size_in_bytes(cell_count);
|
||||
}
|
||||
|
||||
int MethodData::compute_extra_data_count(int data_size, int empty_bc_count) {
|
||||
bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) {
|
||||
// Bytecodes for which we may use speculation
|
||||
switch (code) {
|
||||
case Bytecodes::_checkcast:
|
||||
case Bytecodes::_instanceof:
|
||||
case Bytecodes::_aastore:
|
||||
case Bytecodes::_invokevirtual:
|
||||
case Bytecodes::_invokeinterface:
|
||||
case Bytecodes::_if_acmpeq:
|
||||
case Bytecodes::_if_acmpne:
|
||||
case Bytecodes::_invokestatic:
|
||||
#ifdef COMPILER2
|
||||
return UseTypeSpeculation;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) {
|
||||
if (ProfileTraps) {
|
||||
// Assume that up to 3% of BCIs with no MDP will need to allocate one.
|
||||
int extra_data_count = (uint)(empty_bc_count * 3) / 128 + 1;
|
||||
|
@ -756,7 +821,18 @@ int MethodData::compute_extra_data_count(int data_size, int empty_bc_count) {
|
|||
extra_data_count = one_percent_of_data;
|
||||
if (extra_data_count > empty_bc_count)
|
||||
extra_data_count = empty_bc_count; // no need for more
|
||||
return extra_data_count;
|
||||
|
||||
// Make sure we have a minimum number of extra data slots to
|
||||
// allocate SpeculativeTrapData entries. We would want to have one
|
||||
// entry per compilation that inlines this method and for which
|
||||
// some type speculation assumption fails. So the room we need for
|
||||
// the SpeculativeTrapData entries doesn't directly depend on the
|
||||
// size of the method. Because it's hard to estimate, we reserve
|
||||
// space for an arbitrary number of entries.
|
||||
int spec_data_count = (needs_speculative_traps ? SpecTrapLimitExtraEntries : 0) *
|
||||
(SpeculativeTrapData::static_cell_count() + DataLayout::header_size_in_cells());
|
||||
|
||||
return MAX2(extra_data_count, spec_data_count);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -769,15 +845,17 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
|
|||
BytecodeStream stream(method);
|
||||
Bytecodes::Code c;
|
||||
int empty_bc_count = 0; // number of bytecodes lacking data
|
||||
bool needs_speculative_traps = false;
|
||||
while ((c = stream.next()) >= 0) {
|
||||
int size_in_bytes = compute_data_size(&stream);
|
||||
data_size += size_in_bytes;
|
||||
if (size_in_bytes == 0) empty_bc_count += 1;
|
||||
needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c);
|
||||
}
|
||||
int object_size = in_bytes(data_offset()) + data_size;
|
||||
|
||||
// Add some extra DataLayout cells (at least one) to track stray traps.
|
||||
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
|
||||
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count, needs_speculative_traps);
|
||||
object_size += extra_data_count * DataLayout::compute_size_in_bytes(0);
|
||||
|
||||
// Add a cell to record information about modified arguments.
|
||||
|
@ -1009,18 +1087,23 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
|
|||
_data[0] = 0; // apparently not set below.
|
||||
BytecodeStream stream(method);
|
||||
Bytecodes::Code c;
|
||||
bool needs_speculative_traps = false;
|
||||
while ((c = stream.next()) >= 0) {
|
||||
int size_in_bytes = initialize_data(&stream, data_size);
|
||||
data_size += size_in_bytes;
|
||||
if (size_in_bytes == 0) empty_bc_count += 1;
|
||||
needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c);
|
||||
}
|
||||
_data_size = data_size;
|
||||
int object_size = in_bytes(data_offset()) + data_size;
|
||||
|
||||
// Add some extra DataLayout cells (at least one) to track stray traps.
|
||||
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
|
||||
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count, needs_speculative_traps);
|
||||
int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0);
|
||||
|
||||
// Let's zero the space for the extra data
|
||||
Copy::zero_to_bytes(((address)_data) + data_size, extra_size);
|
||||
|
||||
// Add a cell to record information about modified arguments.
|
||||
// Set up _args_modified array after traps cells so that
|
||||
// the code for traps cells works.
|
||||
|
@ -1032,17 +1115,17 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
|
|||
int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1);
|
||||
object_size += extra_size + arg_data_size;
|
||||
|
||||
int args_cell = ParametersTypeData::compute_cell_count(method());
|
||||
int parms_cell = ParametersTypeData::compute_cell_count(method());
|
||||
// If we are profiling parameters, we reserver an area near the end
|
||||
// of the MDO after the slots for bytecodes (because there's no bci
|
||||
// for method entry so they don't fit with the framework for the
|
||||
// profiling of bytecodes). We store the offset within the MDO of
|
||||
// this area (or -1 if no parameter is profiled)
|
||||
if (args_cell > 0) {
|
||||
object_size += DataLayout::compute_size_in_bytes(args_cell);
|
||||
if (parms_cell > 0) {
|
||||
object_size += DataLayout::compute_size_in_bytes(parms_cell);
|
||||
_parameters_type_data_di = data_size + extra_size + arg_data_size;
|
||||
DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
|
||||
dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell);
|
||||
dp->initialize(DataLayout::parameters_type_data_tag, 0, parms_cell);
|
||||
} else {
|
||||
_parameters_type_data_di = -1;
|
||||
}
|
||||
|
@ -1133,39 +1216,113 @@ ProfileData* MethodData::bci_to_data(int bci) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return bci_to_extra_data(bci, false);
|
||||
return bci_to_extra_data(bci, NULL, false);
|
||||
}
|
||||
|
||||
// Translate a bci to its corresponding extra data, or NULL.
|
||||
ProfileData* MethodData::bci_to_extra_data(int bci, bool create_if_missing) {
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
DataLayout* avail = NULL;
|
||||
for (; dp < end; dp = next_extra(dp)) {
|
||||
DataLayout* MethodData::next_extra(DataLayout* dp) {
|
||||
int nb_cells = 0;
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::bit_data_tag:
|
||||
case DataLayout::no_tag:
|
||||
nb_cells = BitData::static_cell_count();
|
||||
break;
|
||||
case DataLayout::speculative_trap_data_tag:
|
||||
nb_cells = SpeculativeTrapData::static_cell_count();
|
||||
break;
|
||||
default:
|
||||
fatal(err_msg("unexpected tag %d", dp->tag()));
|
||||
}
|
||||
return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells));
|
||||
}
|
||||
|
||||
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp) {
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
for (;; dp = next_extra(dp)) {
|
||||
assert(dp < end, "moved past end of extra data");
|
||||
// No need for "OrderAccess::load_acquire" ops,
|
||||
// since the data structure is monotonic.
|
||||
if (dp->tag() == DataLayout::no_tag) break;
|
||||
if (dp->tag() == DataLayout::arg_info_data_tag) {
|
||||
dp = end; // ArgInfoData is at the end of extra data section.
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::no_tag:
|
||||
return NULL;
|
||||
case DataLayout::arg_info_data_tag:
|
||||
dp = end;
|
||||
return NULL; // ArgInfoData is at the end of extra data section.
|
||||
case DataLayout::bit_data_tag:
|
||||
if (m == NULL && dp->bci() == bci) {
|
||||
return new BitData(dp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (dp->bci() == bci) {
|
||||
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
|
||||
return new BitData(dp);
|
||||
case DataLayout::speculative_trap_data_tag:
|
||||
if (m != NULL) {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
// data->method() may be null in case of a concurrent
|
||||
// allocation. Assume it's for the same method and use that
|
||||
// entry in that case.
|
||||
if (dp->bci() == bci) {
|
||||
if (data->method() == NULL) {
|
||||
return NULL;
|
||||
} else if (data->method() == m) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal(err_msg("unexpected tag %d", dp->tag()));
|
||||
}
|
||||
}
|
||||
if (create_if_missing && dp < end) {
|
||||
// Allocate this one. There is no mutual exclusion,
|
||||
// so two threads could allocate different BCIs to the
|
||||
// same data layout. This means these extra data
|
||||
// records, like most other MDO contents, must not be
|
||||
// trusted too much.
|
||||
DataLayout temp;
|
||||
temp.initialize(DataLayout::bit_data_tag, bci, 0);
|
||||
dp->release_set_header(temp.header());
|
||||
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
|
||||
//NO: assert(dp->bci() == bci, "no concurrent allocation");
|
||||
return new BitData(dp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Translate a bci to its corresponding extra data, or NULL.
|
||||
ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_missing) {
|
||||
// This code assumes an entry for a SpeculativeTrapData is 2 cells
|
||||
assert(2*DataLayout::compute_size_in_bytes(BitData::static_cell_count()) ==
|
||||
DataLayout::compute_size_in_bytes(SpeculativeTrapData::static_cell_count()),
|
||||
"code needs to be adjusted");
|
||||
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
// Allocation in the extra data space has to be atomic because not
|
||||
// all entries have the same size and non atomic concurrent
|
||||
// allocation would result in a corrupted extra data space.
|
||||
while (true) {
|
||||
ProfileData* result = bci_to_extra_data_helper(bci, m, dp);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (create_if_missing && dp < end) {
|
||||
assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
|
||||
assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
|
||||
u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
|
||||
// SpeculativeTrapData is 2 slots. Make sure we have room.
|
||||
if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
|
||||
return NULL;
|
||||
}
|
||||
DataLayout temp;
|
||||
temp.initialize(tag, bci, 0);
|
||||
// May have been set concurrently
|
||||
if (dp->header() != temp.header() && !dp->atomic_set_header(temp.header())) {
|
||||
// Allocation failure because of concurrent allocation. Try
|
||||
// again.
|
||||
continue;
|
||||
}
|
||||
assert(dp->tag() == tag, "sane");
|
||||
assert(dp->bci() == bci, "no concurrent allocation");
|
||||
if (tag == DataLayout::bit_data_tag) {
|
||||
return new BitData(dp);
|
||||
} else {
|
||||
// If being allocated concurrently, one trap may be lost
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
data->set_method(m);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1210,25 +1367,35 @@ void MethodData::print_data_on(outputStream* st) const {
|
|||
for ( ; is_valid(data); data = next_data(data)) {
|
||||
st->print("%d", dp_to_di(data->dp()));
|
||||
st->fill_to(6);
|
||||
data->print_data_on(st);
|
||||
data->print_data_on(st, this);
|
||||
}
|
||||
st->print_cr("--- Extra data:");
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
for (; dp < end; dp = next_extra(dp)) {
|
||||
for (;; dp = next_extra(dp)) {
|
||||
assert(dp < end, "moved past end of extra data");
|
||||
// No need for "OrderAccess::load_acquire" ops,
|
||||
// since the data structure is monotonic.
|
||||
if (dp->tag() == DataLayout::no_tag) continue;
|
||||
if (dp->tag() == DataLayout::bit_data_tag) {
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::no_tag:
|
||||
continue;
|
||||
case DataLayout::bit_data_tag:
|
||||
data = new BitData(dp);
|
||||
} else {
|
||||
assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo");
|
||||
break;
|
||||
case DataLayout::speculative_trap_data_tag:
|
||||
data = new SpeculativeTrapData(dp);
|
||||
break;
|
||||
case DataLayout::arg_info_data_tag:
|
||||
data = new ArgInfoData(dp);
|
||||
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->fill_to(6);
|
||||
data->print_data_on(st);
|
||||
if (dp >= end) return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1351,3 +1518,110 @@ bool MethodData::profile_parameters_for_method(methodHandle m) {
|
|||
assert(profile_parameters_jsr292_only(), "inconsistent");
|
||||
return m->is_compiled_lambda_form();
|
||||
}
|
||||
|
||||
void MethodData::clean_extra_data_helper(DataLayout* dp, int shift, bool reset) {
|
||||
if (shift == 0) {
|
||||
return;
|
||||
}
|
||||
if (!reset) {
|
||||
// Move all cells of trap entry at dp left by "shift" cells
|
||||
intptr_t* start = (intptr_t*)dp;
|
||||
intptr_t* end = (intptr_t*)next_extra(dp);
|
||||
for (intptr_t* ptr = start; ptr < end; ptr++) {
|
||||
*(ptr-shift) = *ptr;
|
||||
}
|
||||
} else {
|
||||
// Reset "shift" cells stopping at dp
|
||||
intptr_t* start = ((intptr_t*)dp) - shift;
|
||||
intptr_t* end = (intptr_t*)dp;
|
||||
for (intptr_t* ptr = start; ptr < end; ptr++) {
|
||||
*ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove SpeculativeTrapData entries that reference an unloaded
|
||||
// method
|
||||
void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
int shift = 0;
|
||||
for (; dp < end; dp = next_extra(dp)) {
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::speculative_trap_data_tag: {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
Method* m = data->method();
|
||||
assert(m != NULL, "should have a method");
|
||||
if (!m->method_holder()->is_loader_alive(is_alive)) {
|
||||
// "shift" accumulates the number of cells for dead
|
||||
// SpeculativeTrapData entries that have been seen so
|
||||
// far. Following entries must be shifted left by that many
|
||||
// cells to remove the dead SpeculativeTrapData entries.
|
||||
shift += (int)((intptr_t*)next_extra(dp) - (intptr_t*)dp);
|
||||
} else {
|
||||
// Shift this entry left if it follows dead
|
||||
// SpeculativeTrapData entries
|
||||
clean_extra_data_helper(dp, shift);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataLayout::bit_data_tag:
|
||||
// Shift this entry left if it follows dead SpeculativeTrapData
|
||||
// entries
|
||||
clean_extra_data_helper(dp, shift);
|
||||
continue;
|
||||
case DataLayout::no_tag:
|
||||
case DataLayout::arg_info_data_tag:
|
||||
// We are at end of the live trap entries. The previous "shift"
|
||||
// cells contain entries that are either dead or were shifted
|
||||
// left. They need to be reset to no_tag
|
||||
clean_extra_data_helper(dp, shift, true);
|
||||
return;
|
||||
default:
|
||||
fatal(err_msg("unexpected tag %d", dp->tag()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify there's no unloaded method referenced by a
|
||||
// SpeculativeTrapData entry
|
||||
void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
|
||||
#ifdef ASSERT
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
for (; dp < end; dp = next_extra(dp)) {
|
||||
switch(dp->tag()) {
|
||||
case DataLayout::speculative_trap_data_tag: {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
Method* m = data->method();
|
||||
assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist");
|
||||
break;
|
||||
}
|
||||
case DataLayout::bit_data_tag:
|
||||
continue;
|
||||
case DataLayout::no_tag:
|
||||
case DataLayout::arg_info_data_tag:
|
||||
return;
|
||||
default:
|
||||
fatal(err_msg("unexpected tag %d", dp->tag()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MethodData::clean_method_data(BoolObjectClosure* is_alive) {
|
||||
for (ProfileData* data = first_data();
|
||||
is_valid(data);
|
||||
data = next_data(data)) {
|
||||
data->clean_weak_klass_links(is_alive);
|
||||
}
|
||||
ParametersTypeData* parameters = parameters_type_data();
|
||||
if (parameters != NULL) {
|
||||
parameters->clean_weak_klass_links(is_alive);
|
||||
}
|
||||
|
||||
clean_extra_data(is_alive);
|
||||
verify_extra_data_clean(is_alive);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue