Skip to content

Commit

Permalink
8267532: C2: Profile and prune untaken exception handlers
Browse files Browse the repository at this point in the history
8310011: Arena with try-with-resources is slower than it should be

Reviewed-by: thartmann, vlivanov
  • Loading branch information
JornVernee committed Nov 28, 2023
1 parent 464dc3d commit a5ccd3b
Show file tree
Hide file tree
Showing 26 changed files with 755 additions and 110 deletions.
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

1 comment on commit a5ccd3b

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.