-
Notifications
You must be signed in to change notification settings - Fork 109
8357474: [lworld] Consolidate load/store flat inline types #1470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: lworld
Are you sure you want to change the base?
Conversation
👋 Welcome back qamai! A progress list of the required criteria for merging this PR into |
@merykitty This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 1 new commit pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@TobiHartmann) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
Webrevs
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice refactoring, thanks for working on this!
I'll review the code in detail soon but I submitted some testing already which revealed an issue:
compiler/valhalla/inlinetypes/TestArrayNullMarkers.java
-Xcomp -XX:-TieredCompilation -DIgnoreCompilerControls=true
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (/workspace/open/src/hotspot/share/opto/memnode.cpp:3587), pid=2958342, tid=2958358
# assert(Opcode() == st->Opcode() || st->Opcode() == Op_StoreVector || Opcode() == Op_StoreVector || st->Opcode() == Op_StoreVectorScatter || Opcode() == Op_StoreVectorScatter || phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI) || (Opcode() == Op_StoreI && st->Opcode() == Op_StoreL) || (Opcode() == Op_StoreL && st->Opcode() == Op_StoreN) || (st->adr_type()->isa_aryptr() && st->adr_type()->is_aryptr()->is_flat()) || (is_mismatched_access() || st->as_Store()->is_mismatched_access())) failed: no mismatched stores, except on raw memory: StoreB StoreN
#
# JRE version: Java(TM) SE Runtime Environment (25.0) (fastdebug build 25-lworld5ea-LTS-2025-05-22-0636300.tobias.hartmann.valhalla2)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 25-lworld5ea-LTS-2025-05-22-0636300.tobias.hartmann.valhalla2, mixed mode, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V [libjvm.so+0x167db09] StoreNode::Ideal(PhaseGVN*, bool)+0x2a9
Current CompileTask:
C2:18680 865 !b compiler.valhalla.inlinetypes.TestArrayNullMarkers::main (2883 bytes)
Stack: [0x00007f99f351b000,0x00007f99f361b000], sp=0x00007f99f36160b0, free space=1004k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x167db09] StoreNode::Ideal(PhaseGVN*, bool)+0x2a9 (memnode.cpp:3587)
V [libjvm.so+0x185de4d] PhaseIterGVN::transform_old(Node*)+0xbd (phaseX.cpp:668)
V [libjvm.so+0x18530d4] PhaseIterGVN::optimize()+0xb4 (phaseX.cpp:1054)
V [libjvm.so+0xb53b16] Compile::Optimize()+0x326 (compile.cpp:2779)
V [libjvm.so+0xb5773f] Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0x1fef (compile.cpp:874)
V [libjvm.so+0x96db34] C2Compiler::compile_method(ciEnv*, ciMethod*, int, bool, DirectiveSet*)+0x484 (c2compiler.cpp:142)
V [libjvm.so+0xb653f8] CompileBroker::invoke_compiler_on_method(CompileTask*)+0xb58 (compileBroker.cpp:2307)
V [libjvm.so+0xb665b8] CompileBroker::compiler_thread_loop()+0x568 (compileBroker.cpp:1951)
V [libjvm.so+0x10df77b] JavaThread::thread_main_inner()+0x13b (javaThread.cpp:774)
V [libjvm.so+0x1b595c6] Thread::call_run()+0xb6 (thread.cpp:231)
V [libjvm.so+0x17c4af8] thread_native_entry(Thread*)+0x128 (os_linux.cpp:875)
test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java
Outdated
Show resolved
Hide resolved
The failure is due to complications computing the field offset of an array access. When finding the field corresponding to a field offset, we cannot find the null marker because it is not a field inside the element type. There is still one strange case, though, consider this class:
Then, the null marker of |
src/hotspot/share/opto/graphKit.cpp
Outdated
@@ -1877,7 +1877,7 @@ Node* GraphKit::flat_array_element_address(Node*& array, Node* idx, ciInlineKlas | |||
const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); | |||
arytype = arytype->cast_to_exactness(true); | |||
arytype = arytype->cast_to_not_null_free(is_not_null_free); | |||
array = _gvn.transform(new CheckCastPPNode(control(), array, arytype)); | |||
array = _gvn.transform(new CheckCastPPNode(control(), array, arytype, ConstraintCastNode::StrongDependency)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you hit an issue without this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle, when we cast the array to null-free atomic, the result type depends on 2 dominating tests, which are the null-free test and the atomic test. As a result, we cannot use RegularDependency
here, because RegularDependency
means that the cast depends only on the test which is its control input.
bool mismatched = (decorators & C2_MISMATCHED) != 0; | ||
if (base->is_Con() && oop_ptr->is_inlinetypeptr() && !is_array && !mismatched) { | ||
// If the oop to the inline type is constant (static final field), we can | ||
// also treat the fields as constants because the inline type is immutable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this not needed anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the loads we generate can be constant-folded, there is no need for an explicit path here.
if (vk->nof_nonstatic_fields() == 0) { | ||
region = new RegionNode(3); | ||
region->init_req(1, kit->top()); | ||
region->init_req(2, kit->top()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the top init needed? Aren't nullptr
inputs handled the same way in RegionNode::Ideal
etc.?
region->init_req(1, kit->top()); | ||
region->init_req(2, kit->top()); | ||
} else { | ||
region = new RegionNode(4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For simplicity, can't we always have a RegionNode
with 4 inputs here and simply leave in(3)
as top/nullptr if we don't need it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that's right, I forgot about that
src/hotspot/share/opto/parse2.cpp
Outdated
const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); | ||
arytype = arytype->cast_to_exactness(true); | ||
arytype = arytype->cast_to_not_null_free(is_not_null_free); | ||
Node* flat_array = gvn().transform(new CastPPNode(control(), array, arytype)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume you are not using flat_array_element_address
anymore because you don't need the address but only want to cast the array but I think this casting should then be factored out. Also, why don't you need a ConstraintCastNode::StrongDependency
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea, I refactored it into GraphKit::cast_to_flat_array
and the element address can be trivially obtained from array_element_address
.
if (!kit->stopped()) { | ||
assert(vk->has_non_atomic_layout(), ""); | ||
// TODO 8350865 Is the conversion to/from payload folded? We should wire this directly. | ||
// Also remove the PreserveReexecuteState in Parse::array_load when buffering is no longer possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that you removed the convert_to_payload
hack, this comment should be removed, right? Also, buffering should no longer be possible and the referenced code in Parse::array_load
can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you are right, I have done that.
Node* cast = base; | ||
Node* ptr = kit->flat_array_element_address(cast, idx, vk, /* null_free */ false, /* not_null_free */ true, /* atomic */ true); | ||
if (vk->get_field_by_offset(vk->payload_offset(), false) == nullptr && vk->null_marker_offset_in_payload() != 0) { | ||
// TODO 8357612 Weird layout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this would be specific to the layout described in JDK-8357612? Wouldn't we also hit vk->get_field_by_offset(vk->payload_offset(), false) == nullptr
when the null marker is at vk->payload_offset()
which would be totally fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The null marker at vk->payload_offset()
is covered by vk->null_marker_offset_in_payload() == 0
, am I right?
src/hotspot/share/opto/parse2.cpp
Outdated
|
||
ciArrayKlass* array_klass = ciArrayKlass::make(vk, /* flat */ true, is_null_free, maybe_atomic); | ||
const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); | ||
arytype = arytype->cast_to_exactness(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice refactoring! Just noticed this here: IIUC, we don't know whether it's null-free or not here but we still set it to exact (was like that before already) which we should probably not? But it looks like the way we later use the CastPP
in make_from_flat_array()
, it does not cause problems because we will feed it into a nullable/not-null-free and null-free cast which is correctly set as exact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a nice catch, I have updated it to cast to exactness only when is_null_free || is_not_null_free
Thanks for your reviews, I have addressed them. I notice there might be some additional issues here, too:
I will investigate these further. |
I have reworked the functions a little bit to remove the |
Hi,
This patch consolidates loading and storing of flat inline types. This makes it so that
make_from_flat
andstore_flat
will take a pointer to the target location.make_from_flat_array
andstore_flat_array
are split out into their own methods which receive anidx
parameter. This also fixes some issues I theorycrafted:Improper loading/storing of atomic elements in a non-atomic container. This is not supported at the moment but it would be great to prepare for it.
is_naturally_atomic
checksnof_declared_nonstatic_fields
, which is incorrect if the sole field has multiple fields. I refactored it intociInlineKlass
, the decision to do atomic loads/stores is also delegated to the callee, the caller only needs to know whether the operations act as if they are atomic, not whether they are actually executed atomically.null_free
of an oop can only be trusted if the container itself is null-free. For example this case:Then
v.s
cannot be trusted to be non-null becausev
can be null.This also allows straightforward implementation of https://bugs.openjdk.org/browse/JDK-8349110.
Please let me know what you think. Thanks very much.
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/valhalla.git pull/1470/head:pull/1470
$ git checkout pull/1470
Update a local copy of the PR:
$ git checkout pull/1470
$ git pull https://git.openjdk.org/valhalla.git pull/1470/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1470
View PR using the GUI difftool:
$ git pr show -t 1470
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/valhalla/pull/1470.diff
Using Webrev
Link to Webrev Comment