Skip to content
62 changes: 34 additions & 28 deletions src/hotspot/share/opto/graphKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,17 +525,13 @@ void GraphKit::uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptR

}

//------------------------------builtin_throw----------------------------------
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {
bool must_throw = true;

Pair<bool, bool> GraphKit::builtin_throw_applies(Deoptimization::DeoptReason reason) {
// If this particular condition has not yet happened at this
// bytecode, then use the uncommon trap mechanism, and allow for
// a future recompilation if several traps occur here.
// If the throw is hot, try to use a more complicated inline mechanism
// which keeps execution inside the compiled code.
bool treat_throw_as_hot = false;
ciMethodData* md = method()->method_data();

if (ProfileTraps) {
if (too_many_traps(reason)) {
Expand All @@ -547,45 +543,55 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {

// Also, if there is a local exception handler, treat all throws
// as hot if there has been at least one in this method.
if (C->trap_count(reason) != 0
&& method()->method_data()->trap_count(reason) != 0
&& has_exception_handler()) {
treat_throw_as_hot = true;
if (C->trap_count(reason) != 0 && method()->method_data()->trap_count(reason) != 0 && has_exception_handler()) {
treat_throw_as_hot = true;
}
}
return {treat_throw_as_hot && method()->can_omit_stack_trace(), treat_throw_as_hot};
}

//------------------------------builtin_throw----------------------------------
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, ciInstance* exception_object) {
bool must_throw = true;
Pair<bool, bool> applies_and_treat_throw_as_hot = builtin_throw_applies(reason);
bool treat_throw_as_hot = applies_and_treat_throw_as_hot.second;

// If this throw happens frequently, an uncommon trap might cause
// a performance pothole. If there is a local exception handler,
// and if this particular bytecode appears to be deoptimizing often,
// let us handle the throw inline, with a preconstructed instance.
// Note: If the deopt count has blown up, the uncommon trap
// runtime is going to flush this nmethod, not matter what.
if (treat_throw_as_hot && method()->can_omit_stack_trace()) {
if (applies_and_treat_throw_as_hot.first) {
// If the throw is local, we use a pre-existing instance and
// punt on the backtrace. This would lead to a missing backtrace
// (a repeat of 4292742) if the backtrace object is ever asked
// for its backtrace.
// Fixing this remaining case of 4292742 requires some flavor of
// escape analysis. Leave that for the future.
ciInstance* ex_obj = nullptr;
switch (reason) {
case Deoptimization::Reason_null_check:
ex_obj = env()->NullPointerException_instance();
break;
case Deoptimization::Reason_div0_check:
ex_obj = env()->ArithmeticException_instance();
break;
case Deoptimization::Reason_range_check:
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
break;
case Deoptimization::Reason_class_check:
ex_obj = env()->ClassCastException_instance();
break;
case Deoptimization::Reason_array_check:
ex_obj = env()->ArrayStoreException_instance();
break;
default:
break;
if (exception_object != nullptr) {
ex_obj = exception_object;
} else {
switch (reason) {
case Deoptimization::Reason_null_check:
ex_obj = env()->NullPointerException_instance();
break;
case Deoptimization::Reason_div0_check:
ex_obj = env()->ArithmeticException_instance();
break;
case Deoptimization::Reason_range_check:
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
break;
case Deoptimization::Reason_class_check:
ex_obj = env()->ClassCastException_instance();
break;
case Deoptimization::Reason_array_check:
ex_obj = env()->ArrayStoreException_instance();
break;
default:
break;
}
}
if (failing()) { stop(); return; } // exception allocation might fail
if (ex_obj != nullptr) {
Expand Down
5 changes: 4 additions & 1 deletion src/hotspot/share/opto/graphKit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@ class GraphKit : public Phase {

// Helper to throw a built-in exception.
// The JVMS must allow the bytecode to be re-executed via an uncommon trap.
void builtin_throw(Deoptimization::DeoptReason reason);
// If `exception_object` is nullptr, the exception to throw will be guessed based on `reason`
void builtin_throw(Deoptimization::DeoptReason reason, ciInstance* exception_object = nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, introduce a new overload instead.

I suggest to extract Deoptimization::DeoptReason -> ciInstance mapping into a helper method and turn void builtin_throw(Deoptimization::DeoptReason reason) into a wrapper:

void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {
   builtin_throw(reason, exception_on_deopt(reason));
}

// Returns the pair (builtin_throw_applies, throw_is_hot) for builtin_throw usage.
Pair<bool, bool> builtin_throw_applies(Deoptimization::DeoptReason reason);

// Helper to check the JavaThread::_should_post_on_exceptions flag
// and branch to an uncommon_trap if it is true (with the specified reason and must_throw)
Expand Down
21 changes: 16 additions & 5 deletions src/hotspot/share/opto/library_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2017,7 +2017,7 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) {
return true;
}

void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
void LibraryCallKit::inline_math_mathExact(Node* math, Node* test, bool use_builtin_throw) {
Node* bol = _gvn.transform( new BoolNode(test, BoolTest::overflow) );
IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN);
Node* fast_path = _gvn.transform( new IfFalseNode(check));
Expand All @@ -2031,8 +2031,12 @@ void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
set_control(slow_path);
set_i_o(i_o());

uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_maybe_recompile);
if (use_builtin_throw) {
builtin_throw(Deoptimization::Reason_intrinsic, env()->ArithmeticException_instance());
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to unconditionally call builtin_throw(). It should handle uncommon_trap case as well.

What makes sense is to ensure that builtin_throw() doesn't change deoptimization reason. It can be implemented with an extra argument to new GraphKit::builtin_throw overload (e.g., bool allow_deopt_reason_none).

} else {
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_maybe_recompile);
}
}

set_control(fast_path);
Expand All @@ -2042,14 +2046,21 @@ void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
template <typename OverflowOp>
bool LibraryCallKit::inline_math_overflow(Node* arg1, Node* arg2) {
typedef typename OverflowOp::MathOp MathOp;
if (too_many_traps(Deoptimization::Reason_intrinsic)) {
bool use_builtin_throw = false;
if (builtin_throw_applies(Deoptimization::Reason_intrinsic).first) {
// If builtin_throw would work (notably, the throw is hot and we don't care about backtraces),
// instead of bailing out on intrinsic or potentially deopting, let's do that!
use_builtin_throw = true;
} else if (too_many_traps(Deoptimization::Reason_intrinsic)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why too_many_traps(Deoptimization::Reason_intrinsic) check is not enough here?

// It has been already too many times, but we cannot use builtin_throw care (e.g. we care about backtraces),
// so let's bail out intrinsic rather than risking deopting again.
return false;
}

MathOp* mathOp = new MathOp(arg1, arg2);
Node* operation = _gvn.transform( mathOp );
Node* ofcheck = _gvn.transform( new OverflowOp(arg1, arg2) );
inline_math_mathExact(operation, ofcheck);
inline_math_mathExact(operation, ofcheck, use_builtin_throw);
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/library_call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class LibraryCallKit : public GraphKit {
bool inline_math_pow();
template <typename OverflowOp>
bool inline_math_overflow(Node* arg1, Node* arg2);
void inline_math_mathExact(Node* math, Node* test);
void inline_math_mathExact(Node* math, Node* test, bool use_builtin_throw);
bool inline_math_addExactI(bool is_increment);
bool inline_math_addExactL(bool is_increment);
bool inline_math_multiplyExactI();
Expand Down
Loading