Skip to content

Commit 97ed536

Browse files
8346989: C2: deoptimization and re-execution cycle with Math.*Exact in case of frequent overflow
Reviewed-by: thartmann, vlivanov
1 parent 660b17a commit 97ed536

File tree

6 files changed

+786
-76
lines changed

6 files changed

+786
-76
lines changed

src/hotspot/share/opto/graphKit.cpp

Lines changed: 85 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -527,71 +527,29 @@ void GraphKit::uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptR
527527

528528
//------------------------------builtin_throw----------------------------------
529529
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {
530-
bool must_throw = true;
531-
532-
// If this particular condition has not yet happened at this
533-
// bytecode, then use the uncommon trap mechanism, and allow for
534-
// a future recompilation if several traps occur here.
535-
// If the throw is hot, try to use a more complicated inline mechanism
536-
// which keeps execution inside the compiled code.
537-
bool treat_throw_as_hot = false;
538-
ciMethodData* md = method()->method_data();
539-
540-
if (ProfileTraps) {
541-
if (too_many_traps(reason)) {
542-
treat_throw_as_hot = true;
543-
}
544-
// (If there is no MDO at all, assume it is early in
545-
// execution, and that any deopts are part of the
546-
// startup transient, and don't need to be remembered.)
547-
548-
// Also, if there is a local exception handler, treat all throws
549-
// as hot if there has been at least one in this method.
550-
if (C->trap_count(reason) != 0
551-
&& method()->method_data()->trap_count(reason) != 0
552-
&& has_exception_handler()) {
553-
treat_throw_as_hot = true;
554-
}
555-
}
530+
builtin_throw(reason, builtin_throw_exception(reason), /*allow_too_many_traps*/ true);
531+
}
556532

533+
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason,
534+
ciInstance* ex_obj,
535+
bool allow_too_many_traps) {
557536
// If this throw happens frequently, an uncommon trap might cause
558537
// a performance pothole. If there is a local exception handler,
559538
// and if this particular bytecode appears to be deoptimizing often,
560539
// let us handle the throw inline, with a preconstructed instance.
561540
// Note: If the deopt count has blown up, the uncommon trap
562541
// runtime is going to flush this nmethod, not matter what.
563-
if (treat_throw_as_hot && method()->can_omit_stack_trace()) {
564-
// If the throw is local, we use a pre-existing instance and
565-
// punt on the backtrace. This would lead to a missing backtrace
566-
// (a repeat of 4292742) if the backtrace object is ever asked
567-
// for its backtrace.
568-
// Fixing this remaining case of 4292742 requires some flavor of
569-
// escape analysis. Leave that for the future.
570-
ciInstance* ex_obj = nullptr;
571-
switch (reason) {
572-
case Deoptimization::Reason_null_check:
573-
ex_obj = env()->NullPointerException_instance();
574-
break;
575-
case Deoptimization::Reason_div0_check:
576-
ex_obj = env()->ArithmeticException_instance();
577-
break;
578-
case Deoptimization::Reason_range_check:
579-
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
580-
break;
581-
case Deoptimization::Reason_class_check:
582-
ex_obj = env()->ClassCastException_instance();
583-
break;
584-
case Deoptimization::Reason_array_check:
585-
ex_obj = env()->ArrayStoreException_instance();
586-
break;
587-
default:
588-
break;
589-
}
590-
// If we have a preconstructed exception object, use it.
591-
if (ex_obj != nullptr) {
542+
if (is_builtin_throw_hot(reason)) {
543+
if (method()->can_omit_stack_trace() && ex_obj != nullptr) {
544+
// If the throw is local, we use a pre-existing instance and
545+
// punt on the backtrace. This would lead to a missing backtrace
546+
// (a repeat of 4292742) if the backtrace object is ever asked
547+
// for its backtrace.
548+
// Fixing this remaining case of 4292742 requires some flavor of
549+
// escape analysis. Leave that for the future.
592550
if (env()->jvmti_can_post_on_exceptions()) {
593551
// check if we must post exception events, take uncommon trap if so
594-
uncommon_trap_if_should_post_on_exceptions(reason, must_throw);
552+
uncommon_trap_if_should_post_on_exceptions(reason, true /*must_throw*/);
595553
// here if should_post_on_exceptions is false
596554
// continue on with the normal codegen
597555
}
@@ -622,6 +580,18 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {
622580

623581
add_exception_state(make_exception_state(ex_node));
624582
return;
583+
} else if (builtin_throw_too_many_traps(reason, ex_obj)) {
584+
// We cannot afford to take too many traps here. Suffer in the interpreter instead.
585+
assert(allow_too_many_traps, "not allowed");
586+
if (C->log() != nullptr) {
587+
C->log()->elem("hot_throw preallocated='0' reason='%s' mcount='%d'",
588+
Deoptimization::trap_reason_name(reason),
589+
C->trap_count(reason));
590+
}
591+
uncommon_trap(reason, Deoptimization::Action_none,
592+
(ciKlass*) nullptr, (char*) nullptr,
593+
true /*must_throw*/);
594+
return;
625595
}
626596
}
627597

@@ -633,27 +603,72 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason) {
633603
// Usual case: Bail to interpreter.
634604
// Reserve the right to recompile if we haven't seen anything yet.
635605

636-
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : nullptr;
637-
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
638-
if (treat_throw_as_hot
639-
&& (method()->method_data()->trap_recompiled_at(bci(), m)
640-
|| C->too_many_traps(reason))) {
641-
// We cannot afford to take more traps here. Suffer in the interpreter.
642-
if (C->log() != nullptr)
643-
C->log()->elem("hot_throw preallocated='0' reason='%s' mcount='%d'",
644-
Deoptimization::trap_reason_name(reason),
645-
C->trap_count(reason));
646-
action = Deoptimization::Action_none;
647-
}
648-
649606
// "must_throw" prunes the JVM state to include only the stack, if there
650607
// are no local exception handlers. This should cut down on register
651608
// allocation time and code size, by drastically reducing the number
652609
// of in-edges on the call to the uncommon trap.
610+
uncommon_trap(reason, Deoptimization::Action_maybe_recompile,
611+
(ciKlass*) nullptr, (char*) nullptr,
612+
true /*must_throw*/);
613+
}
614+
615+
bool GraphKit::is_builtin_throw_hot(Deoptimization::DeoptReason reason) {
616+
// If this particular condition has not yet happened at this
617+
// bytecode, then use the uncommon trap mechanism, and allow for
618+
// a future recompilation if several traps occur here.
619+
// If the throw is hot, try to use a more complicated inline mechanism
620+
// which keeps execution inside the compiled code.
621+
if (ProfileTraps) {
622+
if (too_many_traps(reason)) {
623+
return true;
624+
}
625+
// (If there is no MDO at all, assume it is early in
626+
// execution, and that any deopts are part of the
627+
// startup transient, and don't need to be remembered.)
628+
629+
// Also, if there is a local exception handler, treat all throws
630+
// as hot if there has been at least one in this method.
631+
if (C->trap_count(reason) != 0 &&
632+
method()->method_data()->trap_count(reason) != 0 &&
633+
has_exception_handler()) {
634+
return true;
635+
}
636+
}
637+
return false;
638+
}
653639

654-
uncommon_trap(reason, action, (ciKlass*)nullptr, (char*)nullptr, must_throw);
640+
bool GraphKit::builtin_throw_too_many_traps(Deoptimization::DeoptReason reason,
641+
ciInstance* ex_obj) {
642+
if (is_builtin_throw_hot(reason)) {
643+
if (method()->can_omit_stack_trace() && ex_obj != nullptr) {
644+
return false; // no traps; throws preallocated exception instead
645+
}
646+
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : nullptr;
647+
if (method()->method_data()->trap_recompiled_at(bci(), m) ||
648+
C->too_many_traps(reason)) {
649+
return true;
650+
}
651+
}
652+
return false;
655653
}
656654

655+
ciInstance* GraphKit::builtin_throw_exception(Deoptimization::DeoptReason reason) const {
656+
// Preallocated exception objects to use when we don't need the backtrace.
657+
switch (reason) {
658+
case Deoptimization::Reason_null_check:
659+
return env()->NullPointerException_instance();
660+
case Deoptimization::Reason_div0_check:
661+
return env()->ArithmeticException_instance();
662+
case Deoptimization::Reason_range_check:
663+
return env()->ArrayIndexOutOfBoundsException_instance();
664+
case Deoptimization::Reason_class_check:
665+
return env()->ClassCastException_instance();
666+
case Deoptimization::Reason_array_check:
667+
return env()->ArrayStoreException_instance();
668+
default:
669+
return nullptr;
670+
}
671+
}
657672

658673
//----------------------------PreserveJVMState---------------------------------
659674
PreserveJVMState::PreserveJVMState(GraphKit* kit, bool clone_map) {

src/hotspot/share/opto/graphKit.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,16 @@ class GraphKit : public Phase {
276276
// Helper to throw a built-in exception.
277277
// The JVMS must allow the bytecode to be re-executed via an uncommon trap.
278278
void builtin_throw(Deoptimization::DeoptReason reason);
279+
void builtin_throw(Deoptimization::DeoptReason reason,
280+
ciInstance* exception_object,
281+
bool allow_too_many_traps);
282+
bool builtin_throw_too_many_traps(Deoptimization::DeoptReason reason,
283+
ciInstance* exception_object);
284+
private:
285+
bool is_builtin_throw_hot(Deoptimization::DeoptReason reason);
286+
ciInstance* builtin_throw_exception(Deoptimization::DeoptReason reason) const;
287+
288+
public:
279289

280290
// Helper to check the JavaThread::_should_post_on_exceptions flag
281291
// and branch to an uncommon_trap if it is true (with the specified reason and must_throw)

src/hotspot/share/opto/library_call.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,14 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) {
20032003
return true;
20042004
}
20052005

2006-
void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
2006+
bool LibraryCallKit::inline_math_mathExact(Node* math, Node* test) {
2007+
if (builtin_throw_too_many_traps(Deoptimization::Reason_intrinsic,
2008+
env()->ArithmeticException_instance())) {
2009+
// It has been already too many times, but we cannot use builtin_throw (e.g. we care about backtraces),
2010+
// so let's bail out intrinsic rather than risking deopting again.
2011+
return false;
2012+
}
2013+
20072014
Node* bol = _gvn.transform( new BoolNode(test, BoolTest::overflow) );
20082015
IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN);
20092016
Node* fast_path = _gvn.transform( new IfFalseNode(check));
@@ -2017,12 +2024,14 @@ void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
20172024
set_control(slow_path);
20182025
set_i_o(i_o());
20192026

2020-
uncommon_trap(Deoptimization::Reason_intrinsic,
2021-
Deoptimization::Action_none);
2027+
builtin_throw(Deoptimization::Reason_intrinsic,
2028+
env()->ArithmeticException_instance(),
2029+
/*allow_too_many_traps*/ false);
20222030
}
20232031

20242032
set_control(fast_path);
20252033
set_result(math);
2034+
return true;
20262035
}
20272036

20282037
template <typename OverflowOp>
@@ -2032,8 +2041,7 @@ bool LibraryCallKit::inline_math_overflow(Node* arg1, Node* arg2) {
20322041
MathOp* mathOp = new MathOp(arg1, arg2);
20332042
Node* operation = _gvn.transform( mathOp );
20342043
Node* ofcheck = _gvn.transform( new OverflowOp(arg1, arg2) );
2035-
inline_math_mathExact(operation, ofcheck);
2036-
return true;
2044+
return inline_math_mathExact(operation, ofcheck);
20372045
}
20382046

20392047
bool LibraryCallKit::inline_math_addExactI(bool is_increment) {

src/hotspot/share/opto/library_call.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class LibraryCallKit : public GraphKit {
209209
bool inline_math_pow();
210210
template <typename OverflowOp>
211211
bool inline_math_overflow(Node* arg1, Node* arg2);
212-
void inline_math_mathExact(Node* math, Node* test);
212+
bool inline_math_mathExact(Node* math, Node* test);
213213
bool inline_math_addExactI(bool is_increment);
214214
bool inline_math_addExactL(bool is_increment);
215215
bool inline_math_multiplyExactI();

0 commit comments

Comments
 (0)