Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8267532: C2: Profile and prune untaken exception handlers #16416

Closed
wants to merge 44 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e695e9d
WIP prune dead catch blocks
JornVernee Oct 25, 2023
0579dfe
add BM
JornVernee Oct 26, 2023
4d9a7d3
avoid allocation when looking up handler data
JornVernee Oct 26, 2023
ed7f38d
implement profiling for C2. JVMCI still to od
JornVernee Oct 27, 2023
a754ecc
fix no handler in NMethod case
JornVernee Oct 27, 2023
de8e155
ad IR test
JornVernee Oct 27, 2023
eeca508
add tail to deopt test
JornVernee Oct 27, 2023
bed0e90
fix parameter profiling crasah
JornVernee Oct 27, 2023
4f657bf
fix failing compiler tests
JornVernee Oct 30, 2023
3bd0325
polish handling of MethodData sections
JornVernee Oct 30, 2023
301365c
Remove redundant ciMethodData::_parameters field
JornVernee Oct 30, 2023
6caa6c5
snapshort ex handler data
JornVernee Oct 30, 2023
f9899d3
fix copyright header
JornVernee Oct 30, 2023
1912332
fix initialization order
JornVernee Oct 30, 2023
e763e69
separate flags for profiling and pruning
JornVernee Oct 30, 2023
93287cb
Explicitly enable tiered compilation in TestPrunedExHandler
JornVernee Oct 30, 2023
12a3a83
disable pruning for OSR compilations. Because java/lang/Thread/virtua…
JornVernee Oct 30, 2023
78837c4
look for monitorexit in pruned blocks
JornVernee Oct 31, 2023
e223d95
add exception handler pruning stress flags
JornVernee Oct 31, 2023
a484206
use ciMethod::has_monitor_bytecodes
JornVernee Oct 31, 2023
a33a905
use has_monitor_bytecodes() in c1 as well
JornVernee Oct 31, 2023
8d3a9aa
Revert "add exception handler pruning stress flags"
JornVernee Oct 31, 2023
d727df7
also set has_monitors when callee is synchronized
JornVernee Oct 31, 2023
f076d66
Revert "Revert "add exception handler pruning stress flags""
JornVernee Oct 31, 2023
fc72073
improve StressPrunedExceptionHandlers comment
JornVernee Oct 31, 2023
d86e98e
beef up test a bit
JornVernee Oct 31, 2023
e6963e5
reduce duplication
JornVernee Oct 31, 2023
059e306
use TWR in foreign benchmarks
JornVernee Nov 1, 2023
764bf3b
add one more test case to see that we have no trap after we hit the u…
JornVernee Nov 2, 2023
3ad93fd
add some assertion to IR test that check for compilation and deoptimi…
JornVernee Nov 2, 2023
ba933df
Add missing spaces to IRNode
JornVernee Nov 6, 2023
7ba5fdb
Add smoke tests for -XX:+StressPrunedExceptionHandlers and -XX:-Profi…
JornVernee Nov 6, 2023
261cdb0
remove leftover comment
JornVernee Nov 6, 2023
2695885
Add @requires vm.debug to test
JornVernee Nov 7, 2023
007664a
track catch block enters in deoptimization code too
JornVernee Nov 7, 2023
3586404
drop ProfileExceptionHandlers flag
JornVernee Nov 14, 2023
86700da
Only use ProfileExceptionHandlers
JornVernee Nov 15, 2023
19d0215
Merge branch 'master' into PruneDeadCatchBlocks
JornVernee Nov 17, 2023
0a5e247
Remove has_monitors fix
JornVernee Nov 17, 2023
bee0553
add too_many_traps check
JornVernee Nov 17, 2023
595bdaa
Revert "add too_many_traps check"
JornVernee Nov 17, 2023
46c9434
fix linux compile
JornVernee Nov 17, 2023
46a74db
rename ex_handler -> exception_handler
JornVernee Nov 23, 2023
dfd5da1
add interpreter profiling specific test cases
JornVernee Nov 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion src/hotspot/share/c1/c1_GraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3506,7 +3506,6 @@ int GraphBuilder::recursive_inline_level(ciMethod* cur_callee) const {
return recur_level;
}


bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) {
const char* msg = nullptr;

Expand Down
64 changes: 51 additions & 13 deletions src/hotspot/share/ci/ciMethodData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
ciMethodData::ciMethodData(MethodData* md)
: ciMetadata(md),
_data_size(0), _extra_data_size(0), _data(nullptr),
_parameters_data_offset(0),
_exception_handlers_data_offset(0),
// Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0.
_hint_di(first_di()),
Expand All @@ -50,8 +52,7 @@ ciMethodData::ciMethodData(MethodData* md)
// Initialize the escape information (to "don't know.");
_eflags(0), _arg_local(0), _arg_stack(0), _arg_returned(0),
_invocation_counter(0),
_orig(),
_parameters(nullptr) {}
_orig() {}

// Check for entries that reference an unloaded method
class PrepareExtraDataClosure : public CleanExtraDataClosure {
Expand Down Expand Up @@ -134,8 +135,16 @@ void ciMethodData::load_remaining_extra_data() {

// Copy the extra data once it is prepared (i.e. cache populated, no release of extra data lock anymore)
Copy::disjoint_words_atomic((HeapWord*) mdo->extra_data_base(),
(HeapWord*)((address) _data + _data_size),
(_extra_data_size - mdo->parameters_size_in_bytes()) / HeapWordSize);
(HeapWord*) extra_data_base(),
// copy everything from extra_data_base() up to parameters_data_base()
pointer_delta(parameters_data_base(), extra_data_base(), HeapWordSize));

// skip parameter data copying. Already done in 'load_data'

// copy exception handler data
Copy::disjoint_words_atomic((HeapWord*) mdo->exception_handler_data_base(),
(HeapWord*) exception_handler_data_base(),
exception_handler_data_size() / HeapWordSize);

// speculative trap entries also hold a pointer to a Method so need to be translated
DataLayout* dp_src = mdo->extra_data_base();
Expand Down Expand Up @@ -195,12 +204,17 @@ bool ciMethodData::load_data() {
// args_data_limit: ---------------------------
// | parameter data entries |
// | ... |
// param_data_limit: ---------------------------
// | ex handler data entries |
// | ... |
// extra_data_limit: ---------------------------
//
// _data_size = extra_data_base - data_base
// _extra_data_size = extra_data_limit - extra_data_base
// total_size = _data_size + _extra_data_size
// args_data_limit = data_base + total_size - parameter_data_size
// args_data_limit = param_data_base
// param_data_limit = exception_handler_data_base
// extra_data_limit = extra_data_limit

#ifndef ZERO
// Some Zero platforms do not have expected alignment, and do not use
Expand All @@ -218,12 +232,15 @@ bool ciMethodData::load_data() {
Copy::disjoint_words_atomic((HeapWord*) mdo->data_base(),
(HeapWord*) _data,
_data_size / HeapWordSize);
// Copy offsets. This is used below
_parameters_data_offset = mdo->parameters_type_data_di();
_exception_handlers_data_offset = mdo->exception_handlers_data_di();

int parameters_data_size = mdo->parameters_size_in_bytes();
if (parameters_data_size > 0) {
// Snapshot the parameter data
Copy::disjoint_words_atomic((HeapWord*) mdo->args_data_limit(),
(HeapWord*) ((address)_data + total_size - parameters_data_size),
Copy::disjoint_words_atomic((HeapWord*) mdo->parameters_data_base(),
(HeapWord*) parameters_data_base(),
parameters_data_size / HeapWordSize);
}
// Traverse the profile data, translating any oops into their
Expand All @@ -237,12 +254,12 @@ bool ciMethodData::load_data() {
data = mdo->next_data(data);
}
if (mdo->parameters_type_data() != nullptr) {
_parameters = data_layout_at(mdo->parameters_type_data_di());
ciParametersTypeData* parameters = new ciParametersTypeData(_parameters);
DataLayout* parameters_data = data_layout_at(_parameters_data_offset);
ciParametersTypeData* parameters = new ciParametersTypeData(parameters_data);
parameters->translate_from(mdo->parameters_type_data());
}

assert((DataLayout*) ((address)_data + total_size - parameters_data_size) == args_data_limit(),
assert((DataLayout*) ((address)_data + total_size - parameters_data_size - exception_handler_data_size()) == args_data_limit(),
"sanity - parameter data starts after the argument data of the single ArgInfoData entry");
load_remaining_extra_data();

Expand Down Expand Up @@ -367,16 +384,24 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) {
return next;
}

DataLayout* ciMethodData::next_data_layout(DataLayout* current) {
DataLayout* ciMethodData::next_data_layout_helper(DataLayout* current, bool extra) {
int current_index = dp_to_di((address)current);
int next_index = current_index + current->size_in_bytes();
if (out_of_bounds(next_index)) {
if (extra ? out_of_bounds_extra(next_index) : out_of_bounds(next_index)) {
return nullptr;
}
DataLayout* next = data_layout_at(next_index);
return next;
}

DataLayout* ciMethodData::next_data_layout(DataLayout* current) {
return next_data_layout_helper(current, false);
}

DataLayout* ciMethodData::next_extra_data_layout(DataLayout* current) {
return next_data_layout_helper(current, true);
}

ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
DataLayout* dp = extra_data_base();
DataLayout* end = args_data_limit();
Expand Down Expand Up @@ -438,6 +463,19 @@ ciProfileData* ciMethodData::bci_to_data(int bci, ciMethod* m) {
return nullptr;
}

ciBitData ciMethodData::exception_handler_bci_to_data(int bci) {
assert(ProfileExceptionHandlers, "not profiling");
assert(_data != nullptr, "must be initialized");
for (DataLayout* data = exception_handler_data_base(); data < exception_handler_data_limit(); data = next_extra_data_layout(data)) {
assert(data != nullptr, "out of bounds?");
if (data->bci() == bci) {
return ciBitData(data);
}
}
// called with invalid bci or wrong Method/MethodData
ShouldNotReachHere();
}

// Conservatively decode the trap_state of a ciProfileData.
int ciMethodData::has_trap_at(ciProfileData* data, int reason) {
typedef Deoptimization::DeoptReason DR_t;
Expand Down Expand Up @@ -612,7 +650,7 @@ uint ciMethodData::arg_modified(int arg) const {
}

ciParametersTypeData* ciMethodData::parameters_type_data() const {
return _parameters != nullptr ? new ciParametersTypeData(_parameters) : nullptr;
return parameter_data_size() != 0 ? new ciParametersTypeData(data_layout_at(_parameters_data_offset)) : nullptr;
}

ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) {
Expand Down
37 changes: 27 additions & 10 deletions src/hotspot/share/ci/ciMethodData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,10 @@ class ciMethodData : public ciMetadata {
// Data entries
intptr_t* _data;

// layout of _data
int _parameters_data_offset;
int _exception_handlers_data_offset;

// Cached hint for data_layout_before()
int _hint_di;

Expand All @@ -403,17 +407,13 @@ class ciMethodData : public ciMetadata {
// Coherent snapshot of original header.
MethodData::CompilerCounters _orig;

// Area dedicated to parameters. null if no parameter profiling for this method.
DataLayout* _parameters;
int parameters_size() const {
return _parameters == nullptr ? 0 : parameters_type_data()->size_in_bytes();
}

ciMethodData(MethodData* md = nullptr);

// Accessors
int data_size() const { return _data_size; }
int extra_data_size() const { return _extra_data_size; }
int parameter_data_size() const { return _exception_handlers_data_offset - _parameters_data_offset; }
int exception_handler_data_size() const { return dp_to_di((address) exception_handler_data_limit()) - _exception_handlers_data_offset; }
intptr_t * data() const { return _data; }

MethodData* get_MethodData() const {
Expand All @@ -425,14 +425,20 @@ class ciMethodData : public ciMetadata {
void print_impl(outputStream* st);

DataLayout* data_layout_at(int data_index) const {
assert(data_index % sizeof(intptr_t) == 0, "unaligned");
assert(data_index % sizeof(intptr_t) == 0, "unaligned: %d", data_index);
return (DataLayout*) (((address)_data) + data_index);
}

bool out_of_bounds(int data_index) {
return data_index >= data_size();
}

bool out_of_bounds_extra(int data_index) {
return data_index < data_size() || data_index >= data_size() + extra_data_size();
}

DataLayout* next_data_layout_helper(DataLayout* current, bool extra);

// hint accessors
int hint_di() const { return _hint_di; }
void set_hint_di(int di) {
Expand Down Expand Up @@ -500,7 +506,7 @@ class ciMethodData : public ciMetadata {
bool load_data();

// Convert a dp (data pointer) to a di (data index).
int dp_to_di(address dp) {
int dp_to_di(address dp) const {
return pointer_delta_as_int(dp, ((address)_data));
}

Expand All @@ -511,17 +517,28 @@ class ciMethodData : public ciMetadata {
ciProfileData* first_data() { return data_at(first_di()); }
ciProfileData* next_data(ciProfileData* current);
DataLayout* next_data_layout(DataLayout* current);
DataLayout* next_extra_data_layout(DataLayout* current);
bool is_valid(ciProfileData* current) { return current != nullptr; }
bool is_valid(DataLayout* current) { return current != nullptr; }

// pointers to sections in _data
// NOTE: these may be called before ciMethodData::load_data
// this works out since everything is initialized to 0 (i.e. there will appear to be no data)
DataLayout* extra_data_base() const { return data_layout_at(data_size()); }
DataLayout* args_data_limit() const { return data_layout_at(data_size() + extra_data_size() -
parameters_size()); }
DataLayout* extra_data_limit() const { return data_layout_at(data_size() + extra_data_size()); }
// pointers to sections in extra data
DataLayout* args_data_limit() const { return parameters_data_base(); }
DataLayout* parameters_data_base() const { return data_layout_at(_parameters_data_offset); }
DataLayout* parameters_data_limit() const { return exception_handler_data_base(); }
DataLayout* exception_handler_data_base() const { return data_layout_at(_exception_handlers_data_offset); }
DataLayout* exception_handler_data_limit() const { return extra_data_limit(); }

// 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 = nullptr);

ciBitData exception_handler_bci_to_data(int bci);

uint overflow_trap_count() const {
return _orig.overflow_trap_count();
}
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/interpreter/interpreterRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ JRT_END
// bci where the exception happened. If the exception was propagated back
// from a call, the expression stack contains the values for the bci at the
// invoke w/o arguments (i.e., as if one were inside the call).
// Note that the implementation of this method assumes it's only called when an exception has actually occured
JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* current, oopDesc* exception))
// We get here after we have unwound from a callee throwing an exception
// into the interpreter. Any deferred stack processing is notified of
Expand Down Expand Up @@ -574,6 +575,7 @@ JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea
} else {
// handler in this method => change bci/bcp to handler bci/bcp and continue there
handler_pc = h_method->code_base() + handler_bci;
h_method->set_exception_handler_entered(handler_bci); // profiling
#ifndef ZERO
set_bcp_and_mdp(handler_pc, current);
continuation = Interpreter::dispatch_table(vtos)[*handler_pc];
Expand Down
10 changes: 10 additions & 0 deletions src/hotspot/share/oops/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,16 @@ bool Method::init_method_counters(MethodCounters* counters) {
return Atomic::replace_if_null(&_method_counters, counters);
}

void Method::set_exception_handler_entered(int handler_bci) {
if (ProfileExceptionHandlers) {
MethodData* mdo = method_data();
if (mdo != nullptr) {
BitData handler_data = mdo->exception_handler_bci_to_data(handler_bci);
handler_data.set_exception_handler_entered();
}
}
}

int Method::extra_stack_words() {
// not an inline function, to avoid a header dependency on Interpreter
return extra_stack_entries() * Interpreter::stackElementSize;
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/oops/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ class Method : public Metadata {
return _method_data;
}

// mark an exception handler as entered (used to prune dead catch blocks in C2)
void set_exception_handler_entered(int handler_bci);

MethodCounters* method_counters() const {
return _method_counters;
}
Expand Down
43 changes: 42 additions & 1 deletion src/hotspot/share/oops/methodData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,12 @@ int MethodData::compute_allocation_size_in_bytes(const methodHandle& method) {
if (args_cell > 0) {
object_size += DataLayout::compute_size_in_bytes(args_cell);
}

if (ProfileExceptionHandlers && method()->has_exception_handler()) {
int num_exception_handlers = method()->exception_table_length();
object_size += num_exception_handlers * single_exception_handler_data_size();
}

return object_size;
}

Expand Down Expand Up @@ -1275,15 +1281,28 @@ void MethodData::initialize() {
// 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)
int parm_data_size = 0;
if (parms_cell > 0) {
object_size += DataLayout::compute_size_in_bytes(parms_cell);
parm_data_size = DataLayout::compute_size_in_bytes(parms_cell);
object_size += parm_data_size;
_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, parms_cell);
} else {
_parameters_type_data_di = no_parameters;
}

_exception_handler_data_di = data_size + extra_size + arg_data_size + parm_data_size;
if (ProfileExceptionHandlers && method()->has_exception_handler()) {
int num_exception_handlers = method()->exception_table_length();
object_size += num_exception_handlers * single_exception_handler_data_size();
ExceptionTableElement* exception_handlers = method()->exception_table_start();
for (int i = 0; i < num_exception_handlers; i++) {
DataLayout *dp = exception_handler_data_at(i);
dp->initialize(DataLayout::bit_data_tag, exception_handlers[i].handler_pc, single_exception_handler_data_cell_count());
}
}

// Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0.
// In that situation, _hint_di is never used, but at
Expand Down Expand Up @@ -1378,6 +1397,28 @@ ProfileData* MethodData::bci_to_data(int bci) {
return bci_to_extra_data(bci, nullptr, false);
}

DataLayout* MethodData::exception_handler_bci_to_data_helper(int bci) {
assert(ProfileExceptionHandlers, "not profiling");
for (int i = 0; i < num_exception_handler_data(); i++) {
DataLayout* exception_handler_data = exception_handler_data_at(i);
if (exception_handler_data->bci() == bci) {
return exception_handler_data;
}
}
return nullptr;
}

BitData* MethodData::exception_handler_bci_to_data_or_null(int bci) {
DataLayout* data = exception_handler_bci_to_data_helper(bci);
return data != nullptr ? new BitData(data) : nullptr;
}

BitData MethodData::exception_handler_bci_to_data(int bci) {
DataLayout* data = exception_handler_bci_to_data_helper(bci);
assert(data != nullptr, "invalid bci");
return BitData(data);
}

DataLayout* MethodData::next_extra(DataLayout* dp) {
int nb_cells = 0;
switch(dp->tag()) {
Expand Down