From 96fefed37f658c3aefd7419dd96ccaa474949a42 Mon Sep 17 00:00:00 2001 From: Theo Weidmann Date: Wed, 29 Jan 2025 15:14:40 +0000 Subject: [PATCH] 8319850: PrintInlining should print which methods are late inlines Reviewed-by: chagedorn, kvn, jsjolen, dlong --- src/hotspot/share/compiler/compileTask.cpp | 70 ++-- src/hotspot/share/compiler/compileTask.hpp | 7 + src/hotspot/share/nmt/nmtTreap.hpp | 26 ++ src/hotspot/share/opto/bytecodeInfo.cpp | 48 +-- src/hotspot/share/opto/callGenerator.cpp | 103 ++--- src/hotspot/share/opto/callGenerator.hpp | 22 +- src/hotspot/share/opto/compile.cpp | 381 ++++++------------ src/hotspot/share/opto/compile.hpp | 51 +-- src/hotspot/share/opto/doCall.cpp | 39 +- src/hotspot/share/opto/library_call.cpp | 23 +- src/hotspot/share/opto/node.cpp | 4 - src/hotspot/share/opto/parse.hpp | 5 +- src/hotspot/share/opto/printinlining.cpp | 109 +++++ src/hotspot/share/opto/printinlining.hpp | 139 +++++++ .../jtreg/compiler/ciReplay/InliningBase.java | 14 +- .../compiler/inlining/LateInlinePrinting.java | 101 +++++ .../TestDuplicatedLateInliningOutput.java | 6 +- 17 files changed, 655 insertions(+), 493 deletions(-) create mode 100644 src/hotspot/share/opto/printinlining.cpp create mode 100644 src/hotspot/share/opto/printinlining.hpp create mode 100644 test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index ee906676a8b..e266a215de1 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -284,21 +284,6 @@ void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, i } } -void CompileTask::print_inline_indent(int inline_level, outputStream* st) { - // 1234567 - st->print(" "); // print timestamp - // 1234 - st->print(" "); // print compilation number - // %s!bn - st->print(" "); // print method attributes - if (TieredCompilation) { - st->print(" "); - } - st->print(" "); // more indent - st->print(" "); // initial inlining indent - for (int i = 0; i < inline_level; i++) st->print(" "); -} - // ------------------------------------------------------------------ // CompileTask::print_compilation void CompileTask::print(outputStream* st, const char* msg, bool short_form, bool cr) { @@ -412,45 +397,76 @@ bool CompileTask::check_break_at_flags() { // ------------------------------------------------------------------ // CompileTask::print_inlining void CompileTask::print_inlining_inner(outputStream* st, ciMethod* method, int inline_level, int bci, InliningResult result, const char* msg) { + print_inlining_header(st, method, inline_level, bci); + print_inlining_inner_message(st, result, msg); + st->cr(); +} + +void CompileTask::print_inlining_header(outputStream* st, ciMethod* method, int inline_level, int bci) { // 1234567 - st->print(" "); // print timestamp + st->print(" "); // print timestamp // 1234 - st->print(" "); // print compilation number + st->print(" "); // print compilation number // method attributes if (method->is_loaded()) { - const char sync_char = method->is_synchronized() ? 's' : ' '; + const char sync_char = method->is_synchronized() ? 's' : ' '; const char exception_char = method->has_exception_handlers() ? '!' : ' '; - const char monitors_char = method->has_monitor_bytecodes() ? 'm' : ' '; + const char monitors_char = method->has_monitor_bytecodes() ? 'm' : ' '; // print method attributes st->print(" %c%c%c ", sync_char, exception_char, monitors_char); } else { // %s!bn - st->print(" "); // print method attributes + st->print(" "); // print method attributes } if (TieredCompilation) { st->print(" "); } - st->print(" "); // more indent - st->print(" "); // initial inlining indent + st->print(" "); // more indent + st->print(" "); // initial inlining indent - for (int i = 0; i < inline_level; i++) st->print(" "); + for (int i = 0; i < inline_level; i++) { + st->print(" "); + } - st->print("@ %d ", bci); // print bci + st->print("@ %d ", bci); // print bci + print_inline_inner_method_info(st, method); +} + +void CompileTask::print_inline_inner_method_info(outputStream* st, ciMethod* method) { method->print_short_name(st); - if (method->is_loaded()) + if (method->is_loaded()) { st->print(" (%d bytes)", method->code_size()); - else + } else { st->print(" (not loaded)"); + } +} +void CompileTask::print_inline_indent(int inline_level, outputStream* st) { + // 1234567 + st->print(" "); // print timestamp + // 1234 + st->print(" "); // print compilation number + // %s!bn + st->print(" "); // print method attributes + if (TieredCompilation) { + st->print(" "); + } + st->print(" "); // more indent + st->print(" "); // initial inlining indent + for (int i = 0; i < inline_level; i++) { + st->print(" "); + } +} + +void CompileTask::print_inlining_inner_message(outputStream* st, InliningResult result, const char* msg) { if (msg != nullptr) { st->print(" %s%s", result == InliningResult::SUCCESS ? "" : "failed to inline: ", msg); } else if (result == InliningResult::FAILURE) { st->print(" %s", "failed to inline"); } - st->cr(); } void CompileTask::print_ul(const char* msg){ diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 18459a06e2b..14591a3abdf 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -236,6 +236,9 @@ public: } static void print_ul(const nmethod* nm, const char* msg = nullptr); + /** + * @deprecated Please rely on Compile::inline_printer. Do not directly write inlining information to tty. + */ static void print_inline_indent(int inline_level, outputStream* st = tty); void print_tty(); @@ -253,7 +256,11 @@ public: bool check_break_at_flags(); + static void print_inlining_header(outputStream* st, ciMethod* method, int inline_level, int bci); static void print_inlining_inner(outputStream* st, ciMethod* method, int inline_level, int bci, InliningResult result, const char* msg = nullptr); + static void print_inline_inner_method_info(outputStream* st, ciMethod* method); + static void print_inlining_inner_message(outputStream* st, InliningResult result, const char* msg); + static void print_inlining_tty(ciMethod* method, int inline_level, int bci, InliningResult result, const char* msg = nullptr) { print_inlining_inner(tty, method, inline_level, bci, result, msg); } diff --git a/src/hotspot/share/nmt/nmtTreap.hpp b/src/hotspot/share/nmt/nmtTreap.hpp index e7cc91eefd9..7e4ad3df95b 100644 --- a/src/hotspot/share/nmt/nmtTreap.hpp +++ b/src/hotspot/share/nmt/nmtTreap.hpp @@ -66,6 +66,8 @@ public: TreapNode* _right; public: + TreapNode(const K& k, uint64_t p) : _priority(p), _key(k), _left(nullptr), _right(nullptr) {} + TreapNode(const K& k, const V& v, uint64_t p) : _priority(p), _key(k), @@ -313,6 +315,30 @@ public: return candidate; } + struct FindResult { + FindResult(TreapNode* node, bool new_node) : node(node), new_node(new_node) {} + TreapNode* const node; + bool const new_node; + }; + + // Finds the node for the given k in the tree or inserts a new node with the default constructed value. + FindResult find(const K& k) { + if (TreapNode* found = find(_root, k)) { + return FindResult(found, false); + } + _node_count++; + // Doesn't exist, make node + void* node_place = _allocator.allocate(sizeof(TreapNode)); + uint64_t prio = prng_next(); + TreapNode* node = new (node_place) TreapNode(k, prio); + + // (LEQ_k, GT_k) + node_pair split_up = split(this->_root, k); + // merge(merge(LEQ_k, EQ_k), GT_k) + this->_root = merge(merge(split_up.left, node), split_up.right); + return FindResult(node, true); + } + TreapNode* closest_gt(const K& key) { TreapNode* candidate = nullptr; TreapNode* pos = _root; diff --git a/src/hotspot/share/opto/bytecodeInfo.cpp b/src/hotspot/share/opto/bytecodeInfo.cpp index 55c72a0c35a..e618a708f61 100644 --- a/src/hotspot/share/opto/bytecodeInfo.cpp +++ b/src/hotspot/share/opto/bytecodeInfo.cpp @@ -113,7 +113,8 @@ static bool is_unboxing_method(ciMethod* callee_method, Compile* C) { // positive filter: should callee be inlined? bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, - int caller_bci, bool& should_delay, ciCallProfile& profile) { + JVMState* caller_jvms, bool& should_delay, ciCallProfile& profile) { + int caller_bci = caller_jvms->bci(); // Allows targeted inlining if (C->directive()->should_inline(callee_method)) { set_msg("force inline by CompileCommand"); @@ -143,9 +144,9 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, // Check for too many throws (and not too huge) if(callee_method->interpreter_throwout_count() > InlineThrowCount && size < InlineThrowMaxSize ) { - if (C->print_inlining() && Verbose) { - CompileTask::print_inline_indent(inline_level()); - tty->print_cr("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); + if (Verbose) { + outputStream* stream = C->inline_printer()->record(callee_method, caller_jvms, InliningResult::SUCCESS); + stream->print("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); } set_msg("many throws"); return true; @@ -168,11 +169,8 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, max_inline_size = C->freq_inline_size(); if (size <= max_inline_size && TraceFrequencyInlining) { - CompileTask::print_inline_indent(inline_level()); - tty->print_cr("Inlined frequent method (freq=%lf):", freq); - CompileTask::print_inline_indent(inline_level()); - callee_method->print(); - tty->cr(); + outputStream* stream = C->inline_printer()->record(callee_method, caller_jvms, InliningResult::SUCCESS); + stream->print("Inlined frequent method (freq=%lf):", freq); } } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. @@ -376,7 +374,7 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, _forced_inline = false; // Reset // 'should_delay' can be overridden during replay compilation - if (!should_inline(callee_method, caller_method, caller_bci, should_delay, profile)) { + if (!should_inline(callee_method, caller_method, jvms, should_delay, profile)) { return false; } // 'should_delay' can be overridden during replay compilation @@ -534,8 +532,9 @@ const char* InlineTree::check_can_parse(ciMethod* callee) { } //------------------------------print_inlining--------------------------------- -void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, - ciMethod* caller_method, bool success) const { +void InlineTree::print_inlining(ciMethod* callee_method, JVMState* jvm, bool success) const { + int caller_bci = jvm->bci(); + ciMethod* caller_method = jvm->method(); const char* inline_msg = msg(); assert(inline_msg != nullptr, "just checking"); if (C->log() != nullptr) { @@ -545,19 +544,11 @@ void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, C->log()->inline_fail(inline_msg); } } - CompileTask::print_inlining_ul(callee_method, inline_level(), - caller_bci, inlining_result_of(success), inline_msg); - if (C->print_inlining()) { - C->print_inlining(callee_method, inline_level(), caller_bci, inlining_result_of(success), inline_msg); - guarantee(callee_method != nullptr, "would crash in CompilerEvent::InlineEvent::post"); - if (Verbose) { - const InlineTree *top = this; - while (top->caller_tree() != nullptr) { top = top->caller_tree(); } - //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); - } - } + CompileTask::print_inlining_ul(callee_method, inline_level(), caller_bci, inlining_result_of(success), inline_msg); + C->inline_printer()->record(callee_method, jvm, inlining_result_of(success), inline_msg); EventCompilerInlining event; if (event.should_commit()) { + guarantee(callee_method != nullptr, "would crash in CompilerEvent::InlineEvent::post"); CompilerEvent::InlineEvent::post(event, C->compile_id(), caller_method->get_Method(), callee_method, success, inline_msg, caller_bci); } } @@ -582,14 +573,14 @@ bool InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, ciCallPro // Do some initial checks. if (!pass_initial_checks(caller_method, caller_bci, callee_method)) { set_msg("failed initial checks"); - print_inlining(callee_method, caller_bci, caller_method, false /* !success */); + print_inlining(callee_method, jvms, false /* !success */); return false; } // Do some parse checks. set_msg(check_can_parse(callee_method)); if (msg() != nullptr) { - print_inlining(callee_method, caller_bci, caller_method, false /* !success */); + print_inlining(callee_method, jvms, false /* !success */); return false; } @@ -601,7 +592,7 @@ bool InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, ciCallPro if (msg() == nullptr) { set_msg("inline (hot)"); } - print_inlining(callee_method, caller_bci, caller_method, true /* success */); + print_inlining(callee_method, jvms, true /* success */); InlineTree* callee_tree = build_inline_tree_for_callee(callee_method, jvms, caller_bci); if (should_delay) { // Record late inlining decision in order to dump it for compiler replay @@ -613,7 +604,7 @@ bool InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, ciCallPro if (msg() == nullptr) { set_msg("too cold to inline"); } - print_inlining(callee_method, caller_bci, caller_method, false /* !success */ ); + print_inlining(callee_method, jvms, false /* !success */); return false; } } @@ -634,8 +625,7 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J max_inline_level_adjust += 1; // don't count method handle calls from java.lang.invoke implementation } if (max_inline_level_adjust != 0 && C->print_inlining() && (Verbose || WizardMode)) { - CompileTask::print_inline_indent(inline_level()); - tty->print_cr(" \\-> discounting inline depth"); + C->inline_printer()->record(callee_method, caller_jvms, InliningResult::SUCCESS, " \\-> discounting inline depth"); } if (max_inline_level_adjust != 0 && C->log()) { int id1 = C->log()->identify(caller_jvms->method()); diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 5126a37d456..ec7117e3568 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -84,7 +84,6 @@ public: JVMState* ParseGenerator::generate(JVMState* jvms) { Compile* C = Compile::current(); - C->print_inlining_update(this); if (is_osr()) { // The JVMS for a OSR has a single argument (see its TypeFunc). @@ -143,7 +142,6 @@ protected: JVMState* DirectCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); - kit.C->print_inlining_update(this); bool is_static = method()->is_static(); address target = is_static ? SharedRuntime::get_resolve_static_call_stub() : SharedRuntime::get_resolve_opt_virtual_call_stub(); @@ -218,8 +216,6 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); Node* receiver = kit.argument(0); - kit.C->print_inlining_update(this); - if (kit.C->log() != nullptr) { kit.C->log()->elem("virtual_call bci='%d'", jvms->bci()); } @@ -353,15 +349,6 @@ class LateInlineCallGenerator : public DirectCallGenerator { return DirectCallGenerator::generate(jvms); } - virtual void print_inlining_late(InliningResult result, const char* msg) { - CallNode* call = call_node(); - Compile* C = Compile::current(); - C->print_inlining_assert_ready(); - C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), result, msg); - C->print_inlining_move_to(this); - C->print_inlining_update_delayed(this); - } - virtual void set_unique_id(jlong id) { _unique_id = id; } @@ -431,9 +418,9 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) assert(!input_not_const, "sanity"); // shouldn't have been scheduled for inlining in the first place if (cg != nullptr) { - if (!allow_inline && (C->print_inlining() || C->print_intrinsics())) { - C->print_inlining(cg->method(), jvms->depth()-1, call_node()->jvms()->bci(), InliningResult::FAILURE, - "late method handle call resolution"); + if (!allow_inline) { + C->inline_printer()->record(cg->method(), call_node()->jvms(), InliningResult::FAILURE, + "late method handle call resolution"); } assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; @@ -499,15 +486,6 @@ class LateInlineVirtualCallGenerator : public VirtualCallGenerator { return new_jvms; } - virtual void print_inlining_late(InliningResult result, const char* msg) { - CallNode* call = call_node(); - Compile* C = Compile::current(); - C->print_inlining_assert_ready(); - C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), result, msg); - C->print_inlining_move_to(this); - C->print_inlining_update_delayed(this); - } - virtual void set_unique_id(jlong id) { _unique_id = id; } @@ -531,20 +509,16 @@ bool LateInlineVirtualCallGenerator::do_late_inline_check(Compile* C, JVMState* Node* receiver = jvms->map()->argument(jvms, 0); const Type* recv_type = C->initial_gvn()->type(receiver); if (recv_type->maybe_null()) { - if (C->print_inlining() || C->print_intrinsics()) { - C->print_inlining(method(), jvms->depth()-1, call_node()->jvms()->bci(), InliningResult::FAILURE, - "late call devirtualization failed (receiver may be null)"); - } + C->inline_printer()->record(method(), call_node()->jvms(), InliningResult::FAILURE, + "late call devirtualization failed (receiver may be null)"); return false; } // Even if inlining is not allowed, a virtual call can be strength-reduced to a direct call. bool allow_inline = C->inlining_incrementally(); if (!allow_inline && _callee->holder()->is_interface()) { // Don't convert the interface call to a direct call guarded by an interface subtype check. - if (C->print_inlining() || C->print_intrinsics()) { - C->print_inlining(method(), jvms->depth()-1, call_node()->jvms()->bci(), InliningResult::FAILURE, - "late call devirtualization failed (interface call)"); - } + C->inline_printer()->record(method(), call_node()->jvms(), InliningResult::FAILURE, + "late call devirtualization failed (interface call)"); return false; } CallGenerator* cg = C->call_generator(_callee, @@ -557,9 +531,8 @@ bool LateInlineVirtualCallGenerator::do_late_inline_check(Compile* C, JVMState* true /*allow_intrinsics*/); if (cg != nullptr) { - if (!allow_inline && (C->print_inlining() || C->print_intrinsics())) { - C->print_inlining(cg->method(), jvms->depth()-1, call_node()->jvms()->bci(), InliningResult::FAILURE, - "late call devirtualization"); + if (!allow_inline) { + C->inline_printer()->record(cg->method(), call_node()->jvms(), InliningResult::FAILURE, "late call devirtualization"); } assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; @@ -682,21 +655,13 @@ void CallGenerator::do_late_inline_helper() { map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1)); } - C->print_inlining_assert_ready(); - - C->print_inlining_move_to(this); - C->log_late_inline(this); // JVMState is ready, so time to perform some checks and prepare for inlining attempt. if (!do_late_inline_check(C, jvms)) { map->disconnect_inputs(C); - C->print_inlining_update_delayed(this); return; } - if (C->print_inlining() && (is_mh_late_inline() || is_virtual_late_inline())) { - C->print_inlining_update_delayed(this); - } // Setup default node notes to be picked up by the inlining Node_Notes* old_nn = C->node_notes_at(call->_idx); @@ -711,6 +676,18 @@ void CallGenerator::do_late_inline_helper() { if (new_jvms == nullptr) return; // no change if (C->failing()) return; + if (is_mh_late_inline()) { + C->inline_printer()->record(method(), jvms, InliningResult::SUCCESS, "late inline succeeded (method handle)"); + } else if (is_string_late_inline()) { + C->inline_printer()->record(method(), jvms, InliningResult::SUCCESS, "late inline succeeded (string method)"); + } else if (is_boxing_late_inline()) { + C->inline_printer()->record(method(), jvms, InliningResult::SUCCESS, "late inline succeeded (boxing method)"); + } else if (is_vector_reboxing_late_inline()) { + C->inline_printer()->record(method(), jvms, InliningResult::SUCCESS, "late inline succeeded (vector reboxing method)"); + } else { + C->inline_printer()->record(method(), jvms, InliningResult::SUCCESS, "late inline succeeded"); + } + // Capture any exceptional control flow GraphKit kit(new_jvms); @@ -782,6 +759,8 @@ class LateInlineBoxingCallGenerator : public LateInlineCallGenerator { return new_jvms; } + virtual bool is_boxing_late_inline() const { return true; } + virtual CallGenerator* with_call_node(CallNode* call) { LateInlineBoxingCallGenerator* cg = new LateInlineBoxingCallGenerator(method(), _inline_cg); cg->set_call_node(call->as_CallStaticJava()); @@ -810,6 +789,8 @@ class LateInlineVectorReboxingCallGenerator : public LateInlineCallGenerator { return new_jvms; } + virtual bool is_vector_reboxing_late_inline() const { return true; } + virtual CallGenerator* with_call_node(CallNode* call) { LateInlineVectorReboxingCallGenerator* cg = new LateInlineVectorReboxingCallGenerator(method(), _inline_cg); cg->set_call_node(call->as_CallStaticJava()); @@ -875,7 +856,6 @@ CallGenerator* CallGenerator::for_guarded_call(ciKlass* guarded_receiver, JVMState* PredictedCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); - kit.C->print_inlining_update(this); PhaseGVN& gvn = kit.gvn(); // We need an explicit receiver null_check before checking its type. // We share a map with the caller, so his JVMS gets adjusted. @@ -1048,8 +1028,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const int vtable_index = Method::invalid_vtable_index; if (!ciMethod::is_consistent_info(callee, target)) { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "signatures mismatch"); + print_inlining_failure(C, callee, jvms, "signatures mismatch"); return nullptr; } @@ -1062,15 +1041,12 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* } else { assert(receiver->bottom_type() == TypePtr::NULL_PTR, "not a null: %s", Type::str(receiver->bottom_type())); - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "receiver is always null"); + print_inlining_failure(C, callee, jvms, "receiver is always null"); } } else { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "receiver not constant"); + print_inlining_failure(C, callee, jvms, "receiver not constant"); } - } - break; + } break; case vmIntrinsics::_linkToVirtual: case vmIntrinsics::_linkToStatic: @@ -1085,8 +1061,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ciMethod* target = oop_ptr->const_oop()->as_member_name()->get_vmtarget(); if (!ciMethod::is_consistent_info(callee, target)) { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "signatures mismatch"); + print_inlining_failure(C, callee, jvms, "signatures mismatch"); return nullptr; } @@ -1101,8 +1076,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* Node* recv = kit.argument(0); Node* casted_recv = kit.maybe_narrow_object_type(recv, signature->accessing_klass()); if (casted_recv->is_top()) { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "argument types mismatch"); + print_inlining_failure(C, callee, jvms, "argument types mismatch"); return nullptr; // FIXME: effectively dead; issue a halt node instead } else if (casted_recv != recv) { kit.set_argument(0, casted_recv); @@ -1115,8 +1089,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* Node* arg = kit.argument(receiver_skip + j); Node* casted_arg = kit.maybe_narrow_object_type(arg, t->as_klass()); if (casted_arg->is_top()) { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "argument types mismatch"); + print_inlining_failure(C, callee, jvms, "argument types mismatch"); return nullptr; // FIXME: effectively dead; issue a halt node instead } else if (casted_arg != arg) { kit.set_argument(receiver_skip + j, casted_arg); @@ -1154,15 +1127,12 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* speculative_receiver_type); return cg; } else { - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "member_name not constant"); + print_inlining_failure(C, callee, jvms, "member_name not constant"); } - } - break; + } break; - case vmIntrinsics::_linkToNative: - print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), - "native call"); + case vmIntrinsics::_linkToNative: + print_inlining_failure(C, callee, jvms, "native call"); break; default: @@ -1410,7 +1380,6 @@ CallGenerator::for_uncommon_trap(ciMethod* m, JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) { GraphKit kit(jvms); - kit.C->print_inlining_update(this); // Take the trap with arguments pushed on the stack. (Cf. null_check_receiver). // Callsite signature can be different from actual method being called (i.e _linkTo* sites). // Use callsite signature always. diff --git a/src/hotspot/share/opto/callGenerator.hpp b/src/hotspot/share/opto/callGenerator.hpp index 77182580207..82b195e0c76 100644 --- a/src/hotspot/share/opto/callGenerator.hpp +++ b/src/hotspot/share/opto/callGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,8 @@ class CallGenerator : public ArenaObj { // same but for method handle calls virtual bool is_mh_late_inline() const { return false; } virtual bool is_string_late_inline() const { return false; } + virtual bool is_boxing_late_inline() const { return false; } + virtual bool is_vector_reboxing_late_inline() const { return false; } virtual bool is_virtual_late_inline() const { return false; } // Replace the call with an inline version of the code @@ -171,28 +173,14 @@ class CallGenerator : public ArenaObj { CallGenerator* cg); virtual Node* generate_predicate(JVMState* jvms, int predicate) { return nullptr; }; - virtual void print_inlining_late(InliningResult result, const char* msg) { ShouldNotReachHere(); } - - static void print_inlining(Compile* C, ciMethod* callee, int inline_level, int bci, const char* msg) { - print_inlining_impl(C, callee, inline_level, bci, InliningResult::SUCCESS, msg); - } - - static void print_inlining_failure(Compile* C, ciMethod* callee, int inline_level, int bci, const char* msg) { - print_inlining_impl(C, callee, inline_level, bci, InliningResult::FAILURE, msg); + static void print_inlining_failure(Compile* C, ciMethod* callee, JVMState* jvms, const char* msg) { + C->inline_printer()->record(callee, jvms, InliningResult::FAILURE, msg); C->log_inline_failure(msg); } static bool is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m); static bool is_inlined_method_handle_intrinsic(ciMethod* caller, int bci, ciMethod* m); static bool is_inlined_method_handle_intrinsic(ciMethod* symbolic_info, ciMethod* m); - -private: - static void print_inlining_impl(Compile* C, ciMethod* callee, int inline_level, int bci, - InliningResult result, const char* msg) { - if (C->print_inlining()) { - C->print_inlining(callee, inline_level, bci, result, msg); - } - } }; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index a96735a15e7..8fb1eda0001 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -610,77 +610,75 @@ void Compile::print_ideal_ir(const char* phase_name) { // the continuation bci for on stack replacement. -Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, - Options options, DirectiveSet* directive) - : Phase(Compiler), - _compile_id(ci_env->compile_id()), - _options(options), - _method(target), - _entry_bci(osr_bci), - _ilt(nullptr), - _stub_function(nullptr), - _stub_name(nullptr), - _stub_entry_point(nullptr), - _max_node_limit(MaxNodeLimit), - _post_loop_opts_phase(false), - _allow_macro_nodes(true), - _inlining_progress(false), - _inlining_incrementally(false), - _do_cleanup(false), - _has_reserved_stack_access(target->has_reserved_stack_access()), +Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, + Options options, DirectiveSet* directive) + : Phase(Compiler), + _compile_id(ci_env->compile_id()), + _options(options), + _method(target), + _entry_bci(osr_bci), + _ilt(nullptr), + _stub_function(nullptr), + _stub_name(nullptr), + _stub_entry_point(nullptr), + _max_node_limit(MaxNodeLimit), + _post_loop_opts_phase(false), + _allow_macro_nodes(true), + _inlining_progress(false), + _inlining_incrementally(false), + _do_cleanup(false), + _has_reserved_stack_access(target->has_reserved_stack_access()), #ifndef PRODUCT - _igv_idx(0), - _trace_opto_output(directive->TraceOptoOutputOption), + _igv_idx(0), + _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), - _clinit_barrier_on_entry(false), - _stress_seed(0), - _comp_arena(mtCompiler), - _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), - _env(ci_env), - _directive(directive), - _log(ci_env->log()), - _first_failure_details(nullptr), - _intrinsics (comp_arena(), 0, 0, nullptr), - _macro_nodes (comp_arena(), 8, 0, nullptr), - _parse_predicates (comp_arena(), 8, 0, nullptr), - _template_assertion_predicate_opaqs (comp_arena(), 8, 0, nullptr), - _expensive_nodes (comp_arena(), 8, 0, nullptr), - _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), - _unstable_if_traps (comp_arena(), 8, 0, nullptr), - _coarsened_locks (comp_arena(), 8, 0, nullptr), - _congraph(nullptr), - NOT_PRODUCT(_igv_printer(nullptr) COMMA) - _unique(0), - _dead_node_count(0), - _dead_node_list(comp_arena()), - _node_arena_one(mtCompiler, Arena::Tag::tag_node), - _node_arena_two(mtCompiler, Arena::Tag::tag_node), - _node_arena(&_node_arena_one), - _mach_constant_base_node(nullptr), - _Compile_types(mtCompiler), - _initial_gvn(nullptr), - _igvn_worklist(nullptr), - _types(nullptr), - _node_hash(nullptr), - _late_inlines(comp_arena(), 2, 0, nullptr), - _string_late_inlines(comp_arena(), 2, 0, nullptr), - _boxing_late_inlines(comp_arena(), 2, 0, nullptr), - _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), - _late_inlines_pos(0), - _number_of_mh_late_inlines(0), - _oom(false), - _print_inlining_stream(new (mtCompiler) stringStream()), - _print_inlining_list(nullptr), - _print_inlining_idx(0), - _print_inlining_output(nullptr), - _replay_inline_data(nullptr), - _java_calls(0), - _inner_loops(0), - _interpreter_frame_size(0), - _output(nullptr) + _has_method_handle_invokes(false), + _clinit_barrier_on_entry(false), + _stress_seed(0), + _comp_arena(mtCompiler), + _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), + _env(ci_env), + _directive(directive), + _log(ci_env->log()), + _first_failure_details(nullptr), + _intrinsics(comp_arena(), 0, 0, nullptr), + _macro_nodes(comp_arena(), 8, 0, nullptr), + _parse_predicates(comp_arena(), 8, 0, nullptr), + _template_assertion_predicate_opaqs(comp_arena(), 8, 0, nullptr), + _expensive_nodes(comp_arena(), 8, 0, nullptr), + _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), + _unstable_if_traps(comp_arena(), 8, 0, nullptr), + _coarsened_locks(comp_arena(), 8, 0, nullptr), + _congraph(nullptr), + NOT_PRODUCT(_igv_printer(nullptr) COMMA) + _unique(0), + _dead_node_count(0), + _dead_node_list(comp_arena()), + _node_arena_one(mtCompiler, Arena::Tag::tag_node), + _node_arena_two(mtCompiler, Arena::Tag::tag_node), + _node_arena(&_node_arena_one), + _mach_constant_base_node(nullptr), + _Compile_types(mtCompiler), + _initial_gvn(nullptr), + _igvn_worklist(nullptr), + _types(nullptr), + _node_hash(nullptr), + _late_inlines(comp_arena(), 2, 0, nullptr), + _string_late_inlines(comp_arena(), 2, 0, nullptr), + _boxing_late_inlines(comp_arena(), 2, 0, nullptr), + _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), + _late_inlines_pos(0), + _number_of_mh_late_inlines(0), + _oom(false), + _replay_inline_data(nullptr), + _inline_printer(this), + _java_calls(0), + _inner_loops(0), + _interpreter_frame_size(0), + _output(nullptr) #ifndef PRODUCT - , _in_dump_cnt(0) + , + _in_dump_cnt(0) #endif { C = this; @@ -743,7 +741,6 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, PhaseGVN gvn; set_initial_gvn(&gvn); - print_inlining_init(); { // Scope for timing the parser TracePhase tp(_t_parser); @@ -886,71 +883,68 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, //------------------------------Compile---------------------------------------- // Compile a runtime stub -Compile::Compile( ciEnv* ci_env, - TypeFunc_generator generator, - address stub_function, - const char *stub_name, - int is_fancy_jump, - bool pass_tls, - bool return_pc, - DirectiveSet* directive) - : Phase(Compiler), - _compile_id(0), - _options(Options::for_runtime_stub()), - _method(nullptr), - _entry_bci(InvocationEntryBci), - _stub_function(stub_function), - _stub_name(stub_name), - _stub_entry_point(nullptr), - _max_node_limit(MaxNodeLimit), - _post_loop_opts_phase(false), - _allow_macro_nodes(true), - _inlining_progress(false), - _inlining_incrementally(false), - _has_reserved_stack_access(false), +Compile::Compile(ciEnv* ci_env, + TypeFunc_generator generator, + address stub_function, + const char* stub_name, + int is_fancy_jump, + bool pass_tls, + bool return_pc, + DirectiveSet* directive) + : Phase(Compiler), + _compile_id(0), + _options(Options::for_runtime_stub()), + _method(nullptr), + _entry_bci(InvocationEntryBci), + _stub_function(stub_function), + _stub_name(stub_name), + _stub_entry_point(nullptr), + _max_node_limit(MaxNodeLimit), + _post_loop_opts_phase(false), + _allow_macro_nodes(true), + _inlining_progress(false), + _inlining_incrementally(false), + _has_reserved_stack_access(false), #ifndef PRODUCT - _igv_idx(0), - _trace_opto_output(directive->TraceOptoOutputOption), + _igv_idx(0), + _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), - _clinit_barrier_on_entry(false), - _stress_seed(0), - _comp_arena(mtCompiler), - _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), - _env(ci_env), - _directive(directive), - _log(ci_env->log()), - _first_failure_details(nullptr), - _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), - _congraph(nullptr), - NOT_PRODUCT(_igv_printer(nullptr) COMMA) - _unique(0), - _dead_node_count(0), - _dead_node_list(comp_arena()), - _node_arena_one(mtCompiler), - _node_arena_two(mtCompiler), - _node_arena(&_node_arena_one), - _mach_constant_base_node(nullptr), - _Compile_types(mtCompiler), - _initial_gvn(nullptr), - _igvn_worklist(nullptr), - _types(nullptr), - _node_hash(nullptr), - _number_of_mh_late_inlines(0), - _oom(false), - _print_inlining_stream(new (mtCompiler) stringStream()), - _print_inlining_list(nullptr), - _print_inlining_idx(0), - _print_inlining_output(nullptr), - _replay_inline_data(nullptr), - _java_calls(0), - _inner_loops(0), - _interpreter_frame_size(0), - _output(nullptr), + _has_method_handle_invokes(false), + _clinit_barrier_on_entry(false), + _stress_seed(0), + _comp_arena(mtCompiler), + _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), + _env(ci_env), + _directive(directive), + _log(ci_env->log()), + _first_failure_details(nullptr), + _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), + _congraph(nullptr), + NOT_PRODUCT(_igv_printer(nullptr) COMMA) + _unique(0), + _dead_node_count(0), + _dead_node_list(comp_arena()), + _node_arena_one(mtCompiler), + _node_arena_two(mtCompiler), + _node_arena(&_node_arena_one), + _mach_constant_base_node(nullptr), + _Compile_types(mtCompiler), + _initial_gvn(nullptr), + _igvn_worklist(nullptr), + _types(nullptr), + _node_hash(nullptr), + _number_of_mh_late_inlines(0), + _oom(false), + _replay_inline_data(nullptr), + _inline_printer(this), + _java_calls(0), + _inner_loops(0), + _interpreter_frame_size(0), + _output(nullptr), #ifndef PRODUCT - _in_dump_cnt(0), + _in_dump_cnt(0), #endif - _allowed_reasons(0) { + _allowed_reasons(0) { C = this; TraceTime t1(nullptr, &_t_totalCompilation, CITime, false); @@ -991,7 +985,6 @@ Compile::Compile( ciEnv* ci_env, } Compile::~Compile() { - delete _print_inlining_stream; delete _first_failure_details; }; @@ -2112,7 +2105,7 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { CallGenerator* cg = _late_inlines.at(i); const char* msg = "live nodes > LiveNodeCountInliningCutoff"; if (do_print_inlining) { - cg->print_inlining_late(InliningResult::FAILURE, msg); + inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE, msg); } log_late_inline_failure(cg, msg); } @@ -2232,8 +2225,6 @@ void Compile::Optimize() { ResourceMark rm; - print_inlining_reinit(); - NOT_PRODUCT( verify_graph_edges(); ) print_method(PHASE_AFTER_PARSING, 1); @@ -2484,8 +2475,6 @@ void Compile::Optimize() { check_no_dead_use(); - process_print_inlining(); - // We will never use the NodeHash table any more. Clear it so that final_graph_reshaping does not have // to remove hashes to unlock nodes for modifications. C->node_hash()->clear(); @@ -4439,126 +4428,8 @@ Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* return phase->transform(new ConvI2LNode(value, ltype)); } -// The message about the current inlining is accumulated in -// _print_inlining_stream and transferred into the _print_inlining_list -// once we know whether inlining succeeds or not. For regular -// inlining, messages are appended to the buffer pointed by -// _print_inlining_idx in the _print_inlining_list. For late inlining, -// a new buffer is added after _print_inlining_idx in the list. This -// way we can update the inlining message for late inlining call site -// when the inlining is attempted again. -void Compile::print_inlining_init() { - if (print_inlining() || print_intrinsics()) { - // print_inlining_init is actually called several times. - print_inlining_reset(); - _print_inlining_list = new (comp_arena())GrowableArray(comp_arena(), 1, 1, new PrintInliningBuffer()); - } -} - -void Compile::print_inlining_reinit() { - if (print_inlining() || print_intrinsics()) { - print_inlining_reset(); - } -} - -void Compile::print_inlining_reset() { - _print_inlining_stream->reset(); -} - -void Compile::print_inlining_commit() { - assert(print_inlining() || print_intrinsics(), "PrintInlining off?"); - // Transfer the message from _print_inlining_stream to the current - // _print_inlining_list buffer and clear _print_inlining_stream. - _print_inlining_list->at(_print_inlining_idx)->ss()->write(_print_inlining_stream->base(), _print_inlining_stream->size()); - print_inlining_reset(); -} - -void Compile::print_inlining_push() { - // Add new buffer to the _print_inlining_list at current position - _print_inlining_idx++; - _print_inlining_list->insert_before(_print_inlining_idx, new PrintInliningBuffer()); -} - -Compile::PrintInliningBuffer* Compile::print_inlining_current() { - return _print_inlining_list->at(_print_inlining_idx); -} - -void Compile::print_inlining_update(CallGenerator* cg) { - if (print_inlining() || print_intrinsics()) { - if (cg->is_late_inline()) { - if (print_inlining_current()->cg() != cg && - (print_inlining_current()->cg() != nullptr || - print_inlining_current()->ss()->size() != 0)) { - print_inlining_push(); - } - print_inlining_commit(); - print_inlining_current()->set_cg(cg); - } else { - if (print_inlining_current()->cg() != nullptr) { - print_inlining_push(); - } - print_inlining_commit(); - } - } -} - -void Compile::print_inlining_move_to(CallGenerator* cg) { - // We resume inlining at a late inlining call site. Locate the - // corresponding inlining buffer so that we can update it. - if (print_inlining() || print_intrinsics()) { - for (int i = 0; i < _print_inlining_list->length(); i++) { - if (_print_inlining_list->at(i)->cg() == cg) { - _print_inlining_idx = i; - return; - } - } - ShouldNotReachHere(); - } -} - -void Compile::print_inlining_update_delayed(CallGenerator* cg) { - if (print_inlining() || print_intrinsics()) { - assert(_print_inlining_stream->size() > 0, "missing inlining msg"); - assert(print_inlining_current()->cg() == cg, "wrong entry"); - // replace message with new message - _print_inlining_list->at_put(_print_inlining_idx, new PrintInliningBuffer()); - print_inlining_commit(); - print_inlining_current()->set_cg(cg); - } -} - -void Compile::print_inlining_assert_ready() { - assert(!_print_inlining || _print_inlining_stream->size() == 0, "losing data"); -} - -void Compile::process_print_inlining() { - assert(_late_inlines.length() == 0, "not drained yet"); - if (print_inlining() || print_intrinsics()) { - ResourceMark rm; - stringStream ss; - assert(_print_inlining_list != nullptr, "process_print_inlining should be called only once."); - for (int i = 0; i < _print_inlining_list->length(); i++) { - PrintInliningBuffer* pib = _print_inlining_list->at(i); - ss.print("%s", pib->ss()->freeze()); - delete pib; - DEBUG_ONLY(_print_inlining_list->at_put(i, nullptr)); - } - // Reset _print_inlining_list, it only contains destructed objects. - // It is on the arena, so it will be freed when the arena is reset. - _print_inlining_list = nullptr; - // _print_inlining_stream won't be used anymore, either. - print_inlining_reset(); - size_t end = ss.size(); - _print_inlining_output = NEW_ARENA_ARRAY(comp_arena(), char, end+1); - strncpy(_print_inlining_output, ss.freeze(), end+1); - _print_inlining_output[end] = 0; - } -} - void Compile::dump_print_inlining() { - if (_print_inlining_output != nullptr) { - tty->print_raw(_print_inlining_output); - } + inline_printer()->print_on(tty); } void Compile::log_late_inline(CallGenerator* cg) { diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 223e7033761..93252891207 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -46,6 +46,7 @@ #include "runtime/vmThread.hpp" #include "utilities/ticks.hpp" #include "utilities/vmEnums.hpp" +#include "opto/printinlining.hpp" class AbstractLockNode; class AddPNode; @@ -472,29 +473,6 @@ private: // "MemLimit" directive was specified and the memory limit was hit during compilation bool _oom; - // Inlining may not happen in parse order which would make - // PrintInlining output confusing. Keep track of PrintInlining - // pieces in order. - class PrintInliningBuffer : public CHeapObj { - private: - CallGenerator* _cg; - stringStream _ss; - static const size_t default_stream_buffer_size = 128; - - public: - PrintInliningBuffer() - : _cg(nullptr), _ss(default_stream_buffer_size) {} - - stringStream* ss() { return &_ss; } - CallGenerator* cg() { return _cg; } - void set_cg(CallGenerator* cg) { _cg = cg; } - }; - - stringStream* _print_inlining_stream; - GrowableArray* _print_inlining_list; - int _print_inlining_idx; - char* _print_inlining_output; - // Only keep nodes in the expensive node list that need to be optimized void cleanup_expensive_nodes(PhaseIterGVN &igvn); // Use for sorting expensive nodes to bring similar nodes together @@ -506,37 +484,17 @@ private: void* _replay_inline_data; // Pointer to data loaded from file - void print_inlining_init(); - void print_inlining_reinit(); - void print_inlining_commit(); - void print_inlining_push(); - PrintInliningBuffer* print_inlining_current(); - void log_late_inline_failure(CallGenerator* cg, const char* msg); DEBUG_ONLY(bool _exception_backedge;) void record_method_not_compilable_oom(); - public: + InlinePrinter _inline_printer; +public: void* barrier_set_state() const { return _barrier_set_state; } - stringStream* print_inlining_stream() { - assert(print_inlining() || print_intrinsics(), "PrintInlining off?"); - return _print_inlining_stream; - } - - void print_inlining_update(CallGenerator* cg); - void print_inlining_update_delayed(CallGenerator* cg); - void print_inlining_move_to(CallGenerator* cg); - void print_inlining_assert_ready(); - void print_inlining_reset(); - - void print_inlining(ciMethod* method, int inline_level, int bci, InliningResult result, const char* msg = nullptr) { - stringStream ss; - CompileTask::print_inlining_inner(&ss, method, inline_level, bci, result, msg); - print_inlining_stream()->print("%s", ss.freeze()); - } + InlinePrinter* inline_printer() { return &_inline_printer; } #ifndef PRODUCT IdealGraphPrinter* igv_printer() { return _igv_printer; } @@ -1100,7 +1058,6 @@ private: void remove_useless_coarsened_locks(Unique_Node_List& useful); - void process_print_inlining(); void dump_print_inlining(); bool over_inlining_cutoff() const { diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 68a799fc6f3..736ed4e676d 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -49,33 +49,40 @@ #include "jfr/jfr.hpp" #endif -static void print_trace_type_profile(outputStream* out, int depth, ciKlass* prof_klass, int site_count, int receiver_count) { - CompileTask::print_inline_indent(depth, out); +static void print_trace_type_profile(outputStream* out, int depth, ciKlass* prof_klass, int site_count, int receiver_count, + bool with_deco) { + if (with_deco) { + CompileTask::print_inline_indent(depth, out); + } out->print(" \\-> TypeProfile (%d/%d counts) = ", receiver_count, site_count); prof_klass->name()->print_symbol_on(out); - out->cr(); + if (with_deco) { + out->cr(); + } } -static void trace_type_profile(Compile* C, ciMethod* method, int depth, int bci, ciMethod* prof_method, - ciKlass* prof_klass, int site_count, int receiver_count) { +static void trace_type_profile(Compile* C, ciMethod* method, JVMState* jvms, + ciMethod* prof_method, ciKlass* prof_klass, int site_count, int receiver_count) { + int depth = jvms->depth() - 1; + int bci = jvms->bci(); if (TraceTypeProfile || C->print_inlining()) { - outputStream* out = tty; if (!C->print_inlining()) { if (!PrintOpto && !PrintCompilation) { method->print_short_name(); tty->cr(); } CompileTask::print_inlining_tty(prof_method, depth, bci, InliningResult::SUCCESS); + print_trace_type_profile(tty, depth, prof_klass, site_count, receiver_count, true); } else { - out = C->print_inlining_stream(); + auto stream = C->inline_printer()->record(method, jvms, InliningResult::SUCCESS); + print_trace_type_profile(stream, depth, prof_klass, site_count, receiver_count, false); } - print_trace_type_profile(out, depth, prof_klass, site_count, receiver_count); } LogTarget(Debug, jit, inlining) lt; if (lt.is_enabled()) { LogStream ls(lt); - print_trace_type_profile(&ls, depth, prof_klass, site_count, receiver_count); + print_trace_type_profile(&ls, depth, prof_klass, site_count, receiver_count, true); } } @@ -294,17 +301,19 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool if (miss_cg != nullptr) { if (next_hit_cg != nullptr) { assert(speculative_receiver_type == nullptr, "shouldn't end up here if we used speculation"); - trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1)); + trace_type_profile(C, jvms->method(), jvms, next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1)); // We don't need to record dependency on a receiver here and below. // Whenever we inline, the dependency is added by Parse::Parse(). miss_cg = CallGenerator::for_predicted_call(profile.receiver(1), miss_cg, next_hit_cg, PROB_MAX); } if (miss_cg != nullptr) { ciKlass* k = speculative_receiver_type != nullptr ? speculative_receiver_type : profile.receiver(0); - trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, k, site_count, receiver_count); + trace_type_profile(C, jvms->method(), jvms, receiver_method, k, site_count, receiver_count); float hit_prob = speculative_receiver_type != nullptr ? 1.0 : profile.receiver_prob(0); CallGenerator* cg = CallGenerator::for_predicted_call(k, miss_cg, hit_cg, hit_prob); - if (cg != nullptr) return cg; + if (cg != nullptr) { + return cg; + } } } } @@ -371,9 +380,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool // Use a more generic tactic, like a simple call. if (call_does_dispatch) { const char* msg = "virtual call"; - if (C->print_inlining()) { - print_inlining(callee, jvms->depth() - 1, jvms->bci(), InliningResult::FAILURE, msg); - } + C->inline_printer()->record(callee, jvms, InliningResult::FAILURE, msg); C->log_inline_failure(msg); if (IncrementalInlineVirtual && allow_inline) { return CallGenerator::for_late_inline_virtual(callee, vtable_index, prof_factor); // attempt to inline through virtual call later @@ -512,8 +519,6 @@ void Parse::do_call() { // our contribution to it is cleaned up right here. kill_dead_locals(); - C->print_inlining_assert_ready(); - // Set frequently used booleans const bool is_virtual = bc() == Bytecodes::_invokevirtual; const bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 58a2fc327d2..9cff3a41f27 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -119,9 +119,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) { const char *inline_msg = is_virtual() ? "(intrinsic, virtual)" : "(intrinsic)"; CompileTask::print_inlining_ul(callee, jvms->depth() - 1, bci, InliningResult::SUCCESS, inline_msg); - if (C->print_intrinsics() || C->print_inlining()) { - C->print_inlining(callee, jvms->depth() - 1, bci, InliningResult::SUCCESS, inline_msg); - } + C->inline_printer()->record(callee, jvms, InliningResult::SUCCESS, inline_msg); C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_worked); if (C->log()) { C->log()->elem("intrinsic id='%s'%s nodes='%d'", @@ -131,7 +129,6 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) { } // Push the result from the inlined method onto the stack. kit.push_result(); - C->print_inlining_update(this); return kit.transfer_exceptions_into_jvms(); } @@ -147,9 +144,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) { : "failed to inline (intrinsic), method not annotated"; } CompileTask::print_inlining_ul(callee, jvms->depth() - 1, bci, InliningResult::FAILURE, msg); - if (C->print_intrinsics() || C->print_inlining()) { - C->print_inlining(callee, jvms->depth() - 1, bci, InliningResult::FAILURE, msg); - } + C->inline_printer()->record(callee, jvms, InliningResult::FAILURE, msg); } else { // Root compile ResourceMark rm; @@ -164,7 +159,6 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) { } } C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed); - C->print_inlining_update(this); return nullptr; } @@ -190,9 +184,8 @@ Node* LibraryIntrinsic::generate_predicate(JVMState* jvms, int predicate) { const char *inline_msg = is_virtual() ? "(intrinsic, virtual, predicate)" : "(intrinsic, predicate)"; CompileTask::print_inlining_ul(callee, jvms->depth() - 1, bci, InliningResult::SUCCESS, inline_msg); - if (C->print_intrinsics() || C->print_inlining()) { - C->print_inlining(callee, jvms->depth() - 1, bci, InliningResult::SUCCESS, inline_msg); - } + C->inline_printer()->record(callee, jvms, InliningResult::SUCCESS, inline_msg); + C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_worked); if (C->log()) { C->log()->elem("predicate_intrinsic id='%s'%s nodes='%d'", @@ -208,9 +201,7 @@ Node* LibraryIntrinsic::generate_predicate(JVMState* jvms, int predicate) { // Not a root compile. const char* msg = "failed to generate predicate for intrinsic"; CompileTask::print_inlining_ul(kit.callee(), jvms->depth() - 1, bci, InliningResult::FAILURE, msg); - if (C->print_intrinsics() || C->print_inlining()) { - C->print_inlining(kit.callee(), jvms->depth() - 1, bci, InliningResult::FAILURE, msg); - } + C->inline_printer()->record(kit.callee(), jvms, InliningResult::FAILURE, msg); } else { // Root compile ResourceMark rm; @@ -220,9 +211,7 @@ Node* LibraryIntrinsic::generate_predicate(JVMState* jvms, int predicate) { is_virtual() ? " (virtual)" : "", bci); const char *msg = msg_stream.freeze(); log_debug(jit, inlining)("%s", msg); - if (C->print_intrinsics() || C->print_inlining()) { - C->print_inlining_stream()->print("%s", msg); - } + C->inline_printer()->record(kit.callee(), jvms, InliningResult::FAILURE, msg); } C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed); return nullptr; diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 89e7ead2c76..583d0ba7601 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -547,10 +547,6 @@ Node *Node::clone() const { if (cg != nullptr) { CallGenerator* cloned_cg = cg->with_call_node(n->as_Call()); n->as_Call()->set_generator(cloned_cg); - - C->print_inlining_assert_ready(); - C->print_inlining_move_to(cg); - C->print_inlining_update(cloned_cg); } } if (n->is_SafePoint()) { diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 579e0a53211..83b211828ce 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -75,7 +75,7 @@ protected: bool& should_delay); bool should_inline(ciMethod* callee_method, ciMethod* caller_method, - int caller_bci, + JVMState* caller_jvms, bool& should_delay, ciCallProfile& profile); bool should_not_inline(ciMethod* callee_method, @@ -87,8 +87,7 @@ protected: ciMethod* caller_method, int caller_bci, ciCallProfile& profile); - void print_inlining(ciMethod* callee_method, int caller_bci, - ciMethod* caller_method, bool success) const; + void print_inlining(ciMethod* callee_method, JVMState* jvm, bool success) const; InlineTree* caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; diff --git a/src/hotspot/share/opto/printinlining.cpp b/src/hotspot/share/opto/printinlining.cpp new file mode 100644 index 00000000000..accc3dcc637 --- /dev/null +++ b/src/hotspot/share/opto/printinlining.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "opto/printinlining.hpp" +#include "opto/callnode.hpp" +#include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" + +bool InlinePrinter::is_enabled() const { + return C->print_intrinsics() || C->print_inlining(); +} + +outputStream* InlinePrinter::record(ciMethod* callee, JVMState* state, InliningResult result, const char* msg) { + if (!is_enabled()) { + return &_nullStream; + } + outputStream* stream = locate(state, callee)->add(result); + if (msg != nullptr) { + stream->print("%s", msg); + } + return stream; // Pointer stays valid, see IPInlineSite::add() +} + +void InlinePrinter::print_on(outputStream* tty) const { + if (!is_enabled()) { + return; + } + _root.dump(tty, -1); +} + +InlinePrinter::IPInlineSite* InlinePrinter::locate(JVMState* state, ciMethod* callee) { + auto growableArray = new GrowableArrayCHeap(2); + + while (state != nullptr) { + growableArray->push(state); + state = state->caller(); + } + + IPInlineSite* site = &_root; + for (int i = growableArray->length() - 1; i >= 0; i--) { + site = &site->at_bci(growableArray->at(i)->bci(), i == 0 ? callee : nullptr); + } + + delete growableArray; + + return site; +} + +InlinePrinter::IPInlineSite& InlinePrinter::IPInlineSite::at_bci(int bci, ciMethod* callee) { + auto find_result = _children.find(bci); + IPInlineSite& child = find_result.node->val(); + + if (find_result.new_node) { + assert(callee != nullptr, "an inline call is missing in the chain up to the root"); + child.set_source(callee, bci); + } else { // We already saw a call at this site before + if (callee != nullptr && callee != child._method) { + outputStream* stream = child.add(InliningResult::SUCCESS); + stream->print("callee changed to "); + CompileTask::print_inline_inner_method_info(stream, callee); + } + } + + return child; +} + +outputStream* InlinePrinter::IPInlineSite::add(InliningResult result) { + _attempts.push(IPInlineAttempt(result)); + return _attempts.last().make_stream(); +} + +void InlinePrinter::IPInlineSite::dump(outputStream* tty, int level) const { + assert(_bci != -999, "trying to dump site without source"); + + if (_attempts.is_nonempty()) { + CompileTask::print_inlining_header(tty, _method, level, _bci); + } + for (int i = 0; i < _attempts.length(); i++) { + CompileTask::print_inlining_inner_message(tty, _attempts.at(i).result(), _attempts.at(i).stream()->base()); + } + if (_attempts.is_nonempty()) { + tty->cr(); + } + + _children.visit_in_order([=](auto* node) { + node->val().dump(tty, level + 1); + }); +} diff --git a/src/hotspot/share/opto/printinlining.hpp b/src/hotspot/share/opto/printinlining.hpp new file mode 100644 index 00000000000..ae79648319b --- /dev/null +++ b/src/hotspot/share/opto/printinlining.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef PRINTINLINING_HPP +#define PRINTINLINING_HPP + +#include "memory/allocation.hpp" +#include "utilities/ostream.hpp" +#include "utilities/growableArray.hpp" +#include "nmt/nmtTreap.hpp" + +class JVMState; +class ciMethod; +class Compile; +enum class InliningResult; + +// If not enabled, all method calls are no-ops. +class InlinePrinter { +private: + class IPInlineAttempt { + InliningResult _result; + stringStream* _stream; + + public: + IPInlineAttempt() : _stream(nullptr) {} + + IPInlineAttempt(InliningResult result) : _result(result), _stream(nullptr) {} + + InliningResult result() const { return _result; } + + stringStream* make_stream() { + assert(_stream == nullptr, "stream already exists"); + _stream = new (mtCompiler) stringStream; + return _stream; + } + + stringStream* stream() const { + assert(_stream != nullptr, "stream was not created yet!"); + return _stream; + } + + void deallocate_stream() { + delete _stream; + _stream = nullptr; + } + }; + + struct Cmp { + static int cmp(int a, int b) { + return a - b; + } + }; + + class IPInlineSite : public CHeapObj { + private: + ciMethod* _method; + int _bci; + GrowableArrayCHeap _attempts; + TreapCHeap _children; + + public: + IPInlineSite(ciMethod* method, int bci) : _method(method), _bci(bci) {} + + IPInlineSite() : _method(nullptr), _bci(-999) {} + + ~IPInlineSite() { + // Since GrowableArrayCHeap uses copy semantics to resize itself we + // cannot free the stream inside IPInlineAttempt's destructor unfortunately + // and have to take care of this here instead. + for (int i = 0; i < _attempts.length(); i++) { + _attempts.at(i).deallocate_stream(); + } + } + + void set_source(ciMethod* method, int bci) { + _method = method; + _bci = bci; + } + + // Finds the node for an inline attempt that occurred inside this inline. + // If this is a new site, provide the callee otherwise null. + // Returned reference is valid until any at_bci is called with non-null callee. + IPInlineSite& at_bci(int bci, ciMethod* callee); + // The returned pointer stays valid until InlinePrinter is destructed. + outputStream* add(InliningResult result); + + void dump(outputStream* tty, int level) const; + }; + + bool is_enabled() const; + + Compile* C; + + // In case print inline is disabled, this null stream is returned from ::record() + nullStream _nullStream; + + // Locates the IPInlineSite node that corresponds to this JVM state. + // state may be null. In this case, the root node is returned. + // If this is a new site, provide the callee otherwise null. + // Returned pointer is valid until InlinePrinter is destructed. + IPInlineSite* locate(JVMState* state, ciMethod* callee); + + IPInlineSite _root{nullptr, 0}; + +public: + InlinePrinter(Compile* compile) : C(compile) {} + + // Saves the result of an inline attempt of method at state. + // An optional string message with more details that is copied to the stream for this attempt. Pointer is not captured. + // Returns an output stream which stores the message associated with this attempt. The buffer stays valid until InlinePrinter is destructed. + // You can print arbitrary information to this stream but do not add line breaks, as this will break formatting. + outputStream* record(ciMethod* callee, JVMState* state, InliningResult result, const char* msg = nullptr); + + // Prints all collected inlining information to the given output stream. + void print_on(outputStream* tty) const; +}; + +#endif // PRINTINLINING_HPP diff --git a/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java b/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java index e3ec7527123..fbe2e89a45d 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java +++ b/test/hotspot/jtreg/compiler/ciReplay/InliningBase.java @@ -86,31 +86,31 @@ public abstract class InliningBase extends DumpReplayBase { } public boolean isNormalInline() { - return reason.equals("inline (hot)"); + return reason.startsWith("inline (hot)"); } public boolean isForcedByReplay() { - return reason.equals("force inline by ciReplay"); + return reason.startsWith("force inline by ciReplay"); } public boolean isDisallowedByReplay() { - return reason.equals("failed to inline: disallowed by ciReplay"); + return reason.startsWith("failed to inline: disallowed by ciReplay"); } public boolean isUnloadedSignatureClasses() { - return reason.equals("failed to inline: unloaded signature classes"); + return reason.startsWith("failed to inline: unloaded signature classes"); } public boolean isForcedIncrementalInlineByReplay() { - return reason.equals("force (incremental) inline by ciReplay"); + return reason.startsWith("force (incremental) inline by ciReplay"); } public boolean isForcedInline() { - return reason.equals("force inline by annotation"); + return reason.startsWith("force inline by annotation"); } public boolean isTooDeep() { - return reason.equals("failed to inline: inlining too deep"); + return reason.startsWith("failed to inline: inlining too deep"); } @Override diff --git a/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java b/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java new file mode 100644 index 00000000000..09ed466f299 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/** + * @test + * @bug 8319850 + * @summary PrintInlining should print which methods are late inlines + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @requires vm.flagless + * + * @run driver compiler.inlining.LateInlinePrinting + */ + +package compiler.inlining; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class LateInlinePrinting { + public static class TestLateInlining { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + private static void test1() { + test3(); + testFailInline(); + testFailInline(); + test2(); + } + + private static void test2() { + inlined1(); + inlined2(); + } + + private static void test3() {} + + private static void testFailInline() {} + + private static void inlined1() {} + + private static void inlined2() {} + } + + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:-TieredCompilation", "-XX:-UseOnStackReplacement", "-XX:-BackgroundCompilation", + "-XX:+PrintCompilation", + "-XX:CompileCommand=compileonly,compiler.inlining.LateInlinePrinting$TestLateInlining::test1", + "-XX:CompileCommand=compileonly,compiler.inlining.LateInlinePrinting$TestLateInlining::test2", + "-XX:CompileCommand=quiet", "-XX:+PrintInlining", "-XX:+AlwaysIncrementalInline", + "-XX:CompileCommand=dontinline,compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline", + TestLateInlining.class.getName() + ); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + analyzer.shouldHaveExitValue(0); + + analyzer.shouldContain(""" +compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes) + @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded + @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded + """); + analyzer.shouldContain(""" +compiler.inlining.LateInlinePrinting$TestLateInlining::test1 (13 bytes) + @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::test3 (1 bytes) inline (hot) late inline succeeded + @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand + @ 6 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand + @ 9 compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes) inline (hot) late inline succeeded + @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded + @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded + """); + } +} diff --git a/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java b/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java index 2b967968ea2..ebc5a827ea4 100644 --- a/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java +++ b/test/hotspot/jtreg/compiler/inlining/TestDuplicatedLateInliningOutput.java @@ -45,12 +45,12 @@ public class TestDuplicatedLateInliningOutput { public static void main(String[] args) throws Exception { test( NonConstantReceiverLauncher.class, - "@ (\\d+)\\s+java\\.lang\\.invoke\\.LambdaForm\\$DMH\\/0x[0-9a-f]+::invokeStatic \\(\\d+ bytes\\)\\s+force inline by annotation", + "@ (\\d+)\\s+java\\.lang\\.invoke\\.MethodHandle::invokeBasic\\(\\)V \\(\\d+ bytes\\)\\s+failed to inline: receiver not constant\\s+callee changed to\\s+java\\.lang\\.invoke\\.LambdaForm\\$DMH\\/0x[0-9a-f]+::invokeStatic \\(\\d+ bytes\\)\\s+force inline by annotation\\s+late inline succeeded \\(method handle\\)", "@ (\\d+)\\s+java\\.lang\\.invoke\\.MethodHandle::invokeBasic\\(\\)V \\(\\d+ bytes\\)\\s+failed to inline: receiver not constant"); test( VirtualCallLauncher.class, - "@ (\\d+)\\s+compiler\\.inlining\\.TestDuplicatedLateInliningOutput\\$VirtualCallLauncher\\$B::lateInlined2 \\(\\d+ bytes\\)\\s+inline \\(hot\\)", + "@ (\\d+)\\s+compiler\\.inlining\\.TestDuplicatedLateInliningOutput\\$VirtualCallLauncher\\$A::lateInlined2 \\(\\d+ bytes\\)\\s+failed to inline: virtual call\\s+callee changed to\\s+\\s+compiler\\.inlining\\.TestDuplicatedLateInliningOutput\\$VirtualCallLauncher\\$B::lateInlined2 \\(\\d+ bytes\\)\\s+inline \\(hot\\)\\s+late inline succeeded", "@ (\\d+)\\s+compiler\\.inlining\\.TestDuplicatedLateInliningOutput\\$VirtualCallLauncher\\$A::lateInlined2 \\(\\d+ bytes\\)\\s+failed to inline: virtual call" ); } @@ -75,7 +75,7 @@ public class TestDuplicatedLateInliningOutput { int index = IntStream.range(0, lines.size()) .filter(i -> lines.get(i).trim().matches(pattern1)) .findFirst() - .orElseThrow(() -> new Exception("No inlining found")); + .orElseThrow(() -> new Exception("No inlining found" + pattern1)); if (lines.get(index - 1).trim().matches(pattern2)) { throw new Exception("Both failure and success message found");