Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
2f10a92
JDK-8302459: compiler/vectorapi/VectorLogicalOpIdentityTest.java fail…
dafedafe Oct 24, 2024
3ba3823
JDK-8302459: remove unused vector inline queue
dafedafe Oct 24, 2024
80901d4
JDK-8302459: remove unneeded changes
dafedafe Oct 24, 2024
7ec8069
JDK-8302459: remove unneeded function declaration
dafedafe Oct 24, 2024
4131271
JDK-8302459: add explicit -TieredCompilation to tests
dafedafe Oct 24, 2024
f29f7a8
JDK-8302459: add bug numbers to tests
dafedafe Oct 24, 2024
a78798c
JDK-8302459: update copyright year
dafedafe Oct 24, 2024
bffdbbd
Revert "JDK-8302459: update copyright year"
dafedafe Nov 4, 2024
7481cc1
Revert "JDK-8302459: add bug numbers to tests"
dafedafe Nov 4, 2024
15cbe15
Revert "JDK-8302459: add explicit -TieredCompilation to tests"
dafedafe Nov 4, 2024
0b7dff8
Revert "JDK-8302459: remove unneeded function declaration"
dafedafe Nov 4, 2024
f547d89
Revert "JDK-8302459: remove unneeded changes"
dafedafe Nov 4, 2024
49c8a51
Revert "JDK-8302459: remove unused vector inline queue"
dafedafe Nov 4, 2024
11c63b5
Revert "JDK-8302459: compiler/vectorapi/VectorLogicalOpIdentityTest.j…
dafedafe Nov 4, 2024
63b749c
JDK-8302459: Missing late inline cleanup causes compiler/vectorapi/Ve…
dafedafe Nov 4, 2024
bd488a9
Merge branch 'master' into JDK-8302459-new
dafedafe Nov 4, 2024
f759c80
JDK-8302459: use list of failed inlines
dafedafe Nov 14, 2024
7064598
JDK-8302459: add flag for inline added callnodes
dafedafe Nov 15, 2024
9f039fd
Merge branch 'master' into JDK-8302459-new
dafedafe Nov 15, 2024
af130f9
JDK-8302459: increment MH late inline counter when reinserting them
dafedafe Nov 20, 2024
ce27ae3
JDK-8302459: remove unneeded spaces
dafedafe Nov 20, 2024
00917c5
JDK-8302459: revert unneeded copyright update
dafedafe Nov 21, 2024
a36199e
JDK-8302459: simplify late inline failure conditions
dafedafe Nov 22, 2024
127a21b
JDK-8302459: copyright year
dafedafe Nov 22, 2024
99eaf0a
JDK-8032459: fix indentation
dafedafe Nov 22, 2024
079d475
JDK-8302459: add failed late inlines handling to dynamic calls
dafedafe Nov 27, 2024
15246bc
JDK-8302459: remove unneeded copyright year change
dafedafe Nov 27, 2024
7a4ffc1
Merge branch 'master' into JDK-8302459-new
dafedafe Nov 27, 2024
b05308f
remove failed late inline tracking
iwanowww Dec 10, 2024
4f0a890
Support repeated inlining attempts for virtual late inlines
iwanowww Dec 11, 2024
13a2d43
Merge branch 'master' into JDK-8302459-new
dafedafe Dec 11, 2024
1c74725
JDK-8302459: add check to avoid infinite loop
dafedafe Dec 12, 2024
a0fb800
JDK-8302459: remove todos
dafedafe Dec 12, 2024
65e7de0
JDK-8302459: add logging
dafedafe Dec 12, 2024
7de8d12
Merge branch 'master' into JDK-8302459-new
dafedafe Feb 19, 2025
f36c5b7
JDK-8302459: fix after merge
dafedafe Feb 20, 2025
1b22923
JDK-8302459: fix copyright year
dafedafe Feb 20, 2025
ba3547d
JDK-8302459: update assert string
dafedafe Feb 27, 2025
2521e85
JDK-8302459: unneeded changes
dafedafe Feb 27, 2025
e71e72f
JDK-8302459: unneeded changes
dafedafe Feb 27, 2025
d688fcf
JDK-8302459: create method to prepend and reset generator
dafedafe Mar 7, 2025
887dd96
JDK-8302459: reshape infinite loop check
dafedafe Mar 10, 2025
9406c6e
JDK-8302459: refactor helper method
dafedafe Mar 10, 2025
bbaf985
Update src/hotspot/share/opto/callnode.cpp
dafedafe Mar 24, 2025
cfa5252
Update src/hotspot/share/opto/callnode.cpp
dafedafe Mar 24, 2025
f84cafb
JDK-8302459: add comments to asserts
dafedafe Mar 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/callGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ class LateInlineVirtualCallGenerator : public VirtualCallGenerator {
virtual void do_late_inline();

virtual void set_callee_method(ciMethod* m) {
assert(_callee == nullptr, "repeated inlining attempt");
assert(_callee == nullptr || _callee == m, "repeated inline attempt with different callee");
_callee = m;
}

Expand Down
119 changes: 72 additions & 47 deletions src/hotspot/share/opto/callnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,15 @@ void CallJavaNode::dump_compact_spec(outputStream* st) const {
}
#endif

void CallJavaNode::register_for_late_inline() {
if (generator() != nullptr) {
Compile::current()->prepend_late_inline(generator());
set_generator(nullptr);
} else {
assert(false, "repeated inline attempt");
}
}

//=============================================================================
uint CallStaticJavaNode::size_of() const { return sizeof(*this); }
bool CallStaticJavaNode::cmp( const Node &n ) const {
Expand All @@ -1079,26 +1088,35 @@ bool CallStaticJavaNode::cmp( const Node &n ) const {
Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) {
CallGenerator* cg = generator();
if (can_reshape && cg != nullptr) {
assert(IncrementalInlineMH, "required");
assert(cg->call_node() == this, "mismatch");
assert(cg->is_mh_late_inline(), "not virtual");

// Check whether this MH handle call becomes a candidate for inlining.
ciMethod* callee = cg->method();
vmIntrinsics::ID iid = callee->intrinsic_id();
if (iid == vmIntrinsics::_invokeBasic) {
if (in(TypeFunc::Parms)->Opcode() == Op_ConP) {
phase->C->prepend_late_inline(cg);
set_generator(nullptr);
if (cg->is_mh_late_inline()) {
assert(IncrementalInlineMH, "required");
assert(cg->call_node() == this, "mismatch");
assert(cg->method()->is_method_handle_intrinsic(), "required");

// Check whether this MH handle call becomes a candidate for inlining.
ciMethod* callee = cg->method();
vmIntrinsics::ID iid = callee->intrinsic_id();
if (iid == vmIntrinsics::_invokeBasic) {
if (in(TypeFunc::Parms)->Opcode() == Op_ConP) {
register_for_late_inline();
}
} else if (iid == vmIntrinsics::_linkToNative) {
// never retry
} else {
assert(callee->has_member_arg(), "wrong type of call?");
if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) {
register_for_late_inline();
phase->C->inc_number_of_mh_late_inlines();
}
}
} else if (iid == vmIntrinsics::_linkToNative) {
// never retry
} else {
assert(callee->has_member_arg(), "wrong type of call?");
if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) {
phase->C->prepend_late_inline(cg);
set_generator(nullptr);
assert(IncrementalInline, "required");
assert(!cg->method()->is_method_handle_intrinsic(), "required");
if (phase->C->print_inlining()) {
phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE,
"static call node changed: trying again");
Copy link
Member

Choose a reason for hiding this comment

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

FTR, could you share how the PrintInlining output looks now when this code is triggered?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like this:

@ 192   jdk.internal.vm.vector.VectorSupport::binaryOp (38 bytes)   failed to inline: failed to inline (intrinsic)   failed to inline: static call node changed: trying again   (intrinsic)   late inline succeeded

It seems a bit redundant: the first failed to inline: failed to inline (intrinsic) doesn't seem to be needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually it is a bit verbose but I would probably leave it like this: the first (failed to inline: failed to inline (intrinsic)) is for the failure and the second (failed to inline: static call node changed: trying again (intrinsic)) is for the retry.

}
register_for_late_inline();
}
}
return CallNode::Ideal(phase, can_reshape);
Expand Down Expand Up @@ -1167,39 +1185,46 @@ bool CallDynamicJavaNode::cmp( const Node &n ) const {
Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) {
CallGenerator* cg = generator();
if (can_reshape && cg != nullptr) {
assert(IncrementalInlineVirtual, "required");
assert(cg->call_node() == this, "mismatch");
assert(cg->is_virtual_late_inline(), "not virtual");

// Recover symbolic info for method resolution.
ciMethod* caller = jvms()->method();
ciBytecodeStream iter(caller);
iter.force_bci(jvms()->bci());

bool not_used1;
ciSignature* not_used2;
ciMethod* orig_callee = iter.get_method(not_used1, &not_used2); // callee in the bytecode
ciKlass* holder = iter.get_declared_method_holder();
if (orig_callee->is_method_handle_intrinsic()) {
assert(_override_symbolic_info, "required");
orig_callee = method();
holder = method()->holder();
}
if (cg->is_virtual_late_inline()) {
assert(IncrementalInlineVirtual, "required");
assert(cg->call_node() == this, "mismatch");

// Recover symbolic info for method resolution.
ciMethod* caller = jvms()->method();
ciBytecodeStream iter(caller);
iter.force_bci(jvms()->bci());

bool not_used1;
ciSignature* not_used2;
ciMethod* orig_callee = iter.get_method(not_used1, &not_used2); // callee in the bytecode
ciKlass* holder = iter.get_declared_method_holder();
if (orig_callee->is_method_handle_intrinsic()) {
assert(_override_symbolic_info, "required");
orig_callee = method();
holder = method()->holder();
}

ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder);
ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder);

Node* receiver_node = in(TypeFunc::Parms);
const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr();
Node* receiver_node = in(TypeFunc::Parms);
const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr();

int not_used3;
bool call_does_dispatch;
ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/,
call_does_dispatch, not_used3); // out-parameters
if (!call_does_dispatch) {
// Register for late inlining.
cg->set_callee_method(callee);
phase->C->prepend_late_inline(cg); // MH late inlining prepends to the list, so do the same
set_generator(nullptr);
int not_used3;
bool call_does_dispatch;
ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/,
call_does_dispatch, not_used3); // out-parameters
if (!call_does_dispatch) {
// Register for late inlining.
cg->set_callee_method(callee);
register_for_late_inline(); // MH late inlining prepends to the list, so do the same
}
} else {
assert(IncrementalInline, "required");
if (phase->C->print_inlining()) {
phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE,
"dynamic call node changed: trying again");
}
register_for_late_inline();
}
}
return CallNode::Ideal(phase, can_reshape);
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/callnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ class CallJavaNode : public CallNode {
void set_arg_escape(bool f) { _arg_escape = f; }
bool arg_escape() const { return _arg_escape; }
void copy_call_debug_info(PhaseIterGVN* phase, SafePointNode *sfpt);
void register_for_late_inline();

DEBUG_ONLY( bool validate_symbolic_info() const; )

Expand Down
11 changes: 11 additions & 0 deletions src/hotspot/share/opto/compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2029,6 +2029,7 @@ bool Compile::inline_incrementally_one() {
for (int i = 0; i < _late_inlines.length(); i++) {
_late_inlines_pos = i+1;
CallGenerator* cg = _late_inlines.at(i);
bool is_scheduled_for_igvn_before = C->igvn_worklist()->member(cg->call_node());
bool does_dispatch = cg->is_virtual_late_inline() || cg->is_mh_late_inline();
if (inlining_incrementally() || does_dispatch) { // a call can be either inlined or strength-reduced to a direct call
cg->do_late_inline();
Expand All @@ -2039,6 +2040,16 @@ bool Compile::inline_incrementally_one() {
_late_inlines_pos = i+1; // restore the position in case new elements were inserted
print_method(PHASE_INCREMENTAL_INLINE_STEP, 3, cg->call_node());
break; // process one call site at a time
} else {
bool is_scheduled_for_igvn_after = C->igvn_worklist()->member(cg->call_node());
if (!is_scheduled_for_igvn_before && is_scheduled_for_igvn_after) {
// Avoid potential infinite loop if node already in the IGVN list
assert(false, "scheduled for IGVN during inlining attempt");
} else {
// Ensure call node has not disappeared from IGVN worklist during a failed inlining attempt
assert(!is_scheduled_for_igvn_before || is_scheduled_for_igvn_after, "call node removed from IGVN list during inlining pass");
cg->call_node()->set_generator(cg);
}
Copy link
Member

Choose a reason for hiding this comment

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

I find this a bit hard to read. Wouldn't it be semantically equivalent to this?

if (is_scheduled_for_igvn_before == is_scheduled_for_igvn_after) {
  cg->call_node()->set_generator(cg);
} else {
  assert(false, "Some useful message");
}

We wouldn't have separate asserts for the two cases, but I think that's fine since one can easily figure it out from the boolean values.

Copy link
Contributor

Choose a reason for hiding this comment

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

The difference is whether a call can be scheduled for a repeated inlining attempt in the future.

cg->call_node()->set_generator(cg) reinitializes cg in CallNode and lets IGVN to submit it for incremental inlining during future passes.

The first check guards against a situation when the call node is already on IGVN list (so, it will be automatically rescheduled for inlining during the next IGVN pass causing an infinite loop in incremental inlining).

The second assert catches a suspicious situation when the call node disappears from IGVN worklist during failed inlining attempt. IMO it should not happens, hence the assert. But it is benign to allow repeated inlining in such case.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, thanks for the background. If we keep both asserts, some comments explaining this would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion!
I've added a couple of comments to the asserts.
I've also changed the second assert into assert(!is_scheduled_for_igvn_before || is_scheduled_for_igvn_after, "call node removed from IGVN list during inlining pass");. The final result is the same but the expression matches what the message says 1-1.

Copy link
Member

Choose a reason for hiding this comment

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

Looks good to me, thanks!

}
} else {
// Ignore late inline direct calls when inlining is not allowed.
Expand Down
1 change: 0 additions & 1 deletion test/hotspot/jtreg/ProblemList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all

compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x
compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x64
compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all

compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* 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
Expand Down Expand Up @@ -32,7 +32,7 @@

/**
* @test
* @bug 8325520
* @bug 8325520 8302459
* @library /test/lib /
* @summary Don't allow folding of Load/Store vectors when using incompatible indices or masks
* @modules jdk.incubator.vector
Expand Down Expand Up @@ -1398,7 +1398,12 @@ public static void testFloatVectorLoadMaskedStoreVector() {
public static void main(String[] args) {
TestFramework testFramework = new TestFramework();
testFramework.setDefaultWarmup(10000)
.addFlags("--add-modules=jdk.incubator.vector", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+IncrementalInlineForceCleanup")
.addFlags("--add-modules=jdk.incubator.vector")
.start();
testFramework = new TestFramework();
testFramework.setDefaultWarmup(10000)
.addFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation")
.start();

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2022, 2023, Arm Limited. All rights reserved.
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
Expand Down Expand Up @@ -41,7 +41,7 @@

/**
* @test
* @bug 8288294
* @bug 8288294 8302459
* @key randomness
* @library /test/lib /
* @summary Add identity transformations for vector logic operations
Expand Down Expand Up @@ -761,5 +761,6 @@ public static void testMaskXorSame() {

public static void main(String[] args) {
TestFramework.runWithFlags("--add-modules=jdk.incubator.vector");
TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-TieredCompilation");
}
}