-
Notifications
You must be signed in to change notification settings - Fork 144
8376221: [lworld] Do not store array of InlineLayoutInfo for all InstanceKlasses #1966
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
8376221: [lworld] Do not store array of InlineLayoutInfo for all InstanceKlasses #1966
Conversation
|
👋 Welcome back jsikstro! A progress list of the required criteria for merging this PR into |
|
@jsikstro 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 115 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. 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 (@stefank, @xmas92, @Arraying, @fparain) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
Webrevs
|
stefank
left a comment
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'm leaving the proper review to Valhalla-devs, but I added a few comments that could be considered.
| if (klass != nullptr) { | ||
| if (klass->is_inline_klass()) { | ||
| _inline_layout_info_array->adr_at(fieldinfo.index())->set_klass(InlineKlass::cast(klass)); | ||
| set_inline_layout_info_klass(fieldinfo.index(), klass, CHECK); |
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 see that this can throw a Metaspace OOME (hence the CHECK) and that we later have this comment:
// Loads triggered by the LoadableDescriptors attribute are speculative, failures must not impact loading of current class
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
Can you verify that using CHECK here is really appropriate? The resolve_super_or_fail uses THREAD, and I think that's what the comment refer to. But with the current patch there's a "returning" call in-between those two parts of the function.
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.
No, I didn't consider any pending exceptions when I added the CHECK. I see that we have an assert(false, ...) down in the Metaspace allocation if there's a pending exception, so we really shouldn't try to allocate the array of InlineLayoutInfo if there's a pending exception, which makes sense.
Looking at the code, I think we should re-arrange it so that we clear any pending exception before calling set_inline_layout_info_klass, while keeping the CHECK so that we exit from ClassFileParser::post_process_parsed_stream if we fail to allocate in Metaspace. This seems to me to be consistent with the old behavior, but it would be nice for someone to fill in 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.
After looking at this for a bit longer I argue that we should never get a resolved klass (non-nullptr) with a pending exception, so the code can be simplified a bit further.
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.
Correct, if SystemDictionary::resolve_super_or_fail() returns a non-null pointer, no exception should have been set by this method, and the methods call before resolve_super_or_fail() have a CHECK argument, ensuring the call to SystemDictionary::resolve_super_or_fail() cannot be reached with a pending exception.
| _must_be_atomic, _layout_info, _inline_layout_info_array); | ||
| lb.build_layout(); | ||
| _has_inline_type_fields = _layout_info->_has_inline_fields; | ||
| _has_inlined_fields = _layout_info->_has_inlined_fields; |
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.
More of a questions to the long-time Valhalla devs: I'm a little curious why the parser has booth of these fields containing the same value?
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.
Historical reasons. The _layout_info structure was added late, and the previous ways to handle inline fields information was not properly refactored.
The ClassFilerParser gets the _layout_info instance before creating the InstanceKlass instance and keeps it until the InstanceKlass instance has been fully initialized, so it is safe to refactor the code to remove ClassFileParser::_has_inline_fields and refactor ClassFilerParser::has_inline_fields() to return _layout_info->_has_inlined_fields.
Note: currently, the only client of ClassFilerParser::has_inline_fields() is the InstanceKlass constructor.
| { | ||
| bool use_atomic_flat = _must_be_atomic; // flatten atomic fields only if the container is itself atomic | ||
| LayoutKind lk = field_layout_selection(fieldinfo, _inline_layout_info_array, use_atomic_flat); | ||
| const int field_index = (int)fieldinfo.index(); |
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.
Are idx and field_index different 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.
I don't think they ever are. I added an assert and ran tier1-3, which never hit. Maybe @fparain can shed some light on this? Otherwise I think we should use field_info.index() in favor of idx and maybe replace the GrowableArrayIterator with a range-based for loop, like this:
for (FieldInfo fi : *_field_info) {
...
}
xmas92
left a comment
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.
Looks good. Just one comment on using a more precis type signature.
A pre-existing issue which I wonder if we can do better. And a general question of how the failure paths are suppose to work for these new pre-loaded classes.
| if (klass != nullptr) { | ||
| if (klass->is_inline_klass()) { | ||
| _inline_layout_info_array->adr_at(fieldinfo.index())->set_klass(InlineKlass::cast(klass)); | ||
| set_inline_layout_info_klass(fieldinfo.index(), klass, CHECK); |
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 think this is a property already precent in the code but this change made me reflect on this.
What are the expected interactions for pre-loaded classes if we fail to load parse the class file which contains them. For example here if we have just resolved the pre-loaded class, and then get metaspace out of memory and stop loading this class file.
Is this the correct (specification wise) interaction for partially failed class file parsing?
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.
There's nothing from the specification point of view that enforces that a class and its pre-loaded (via LoadableDescriptor) classes must be all-or-nothing.
Classes and interfaces mentioned by LoadableDescriptors may optionally be loaded when the referencing class is derived and created (5.3.5), or during early stages of linking (5.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.
This is the same situation as when the JVM is loading a class A, and during the loading of A, it successfully loads A's super-class B, but then encounter an issue while continuing the loading of A (OOM in Metaspace, or B is an interface, or B is final etc.). The loading of A fails, but class B remains in the system dictionary, until its class loader is unloaded.
Arraying
left a comment
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.
Thanks a lot for doing this, the new names are much better and less memory usage is always good. I left some comments, the most pressing one I'd like to resolve is the notion of having flat fields when a value object is buffered.
Arraying
left a comment
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 think this looks good, thanks again for doing it. Maybe it'd be good if @fparain also takes a look at this PR.
| if (!fieldinfo.field_flags().is_injected() && | ||
| ili != nullptr && | ||
| ili->adr_at((int)fieldinfo.index())->klass() != nullptr && | ||
| !ili->adr_at((int)fieldinfo.index())->klass()->is_identity_class()) { |
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.
To be inlineable, the class should not be abstract.
!ili->adr_at((int)fieldinfo.index())->klass()->is_abstract()
would exclude both abstract value classes and interfaces.
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! I'll append that to the checks.
| _klass = klass; | ||
| } | ||
|
|
||
| void ClassFileParser::set_inline_layout_info_klass(int field_index, InstanceKlass* klass, TRAPS) { |
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 method could take an InlineKlass* argument instead of an InstanceKlass* argument, because InlineLayoutInfo can only store information about flat value fields.
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.
Sure, I'll move the InlineKlass::cast() from insdide the method to the callers instead.
fparain
left a comment
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.
Looks good to me.
Thank you for this cleanup.
|
Thank you for the reviews everyone! I merged with the tip of lworld and reran tier1-4 which is green. The failing test in GHA is due to an unrelated issue (solved in JDK-8376358). /integrate |
|
/sponsor |
|
Going to push as commit 53c5531.
Your commit was automatically rebased without conflicts. |
Hello,
Please refer to the JBS issue for a more detailed description of the background of this change. In summary, I suggest we only keep the array of InlineLayoutInfo for InstanceKlasses which need it, which are Klasses that have fields that have been inlined.
To make the transition to this easier, I suggest we change the following properties in FieldLayoutBuilder:
to
The
_has_inlineable_fieldsproperty is only used for printing and_has_inlined_fieldsis the property we expose out to the ClassFileParser, telling us that this class has inlined fields, so the array of InlineLayoutInfo must be "preserved" and is possible to read from. Hence, the array is now only safe to access ifInstanceKlass::has_inlined_fieldsis true, or simply if the actual field being accessed is flat (fieldDescriptor::is_flat).I only found one place (in ciReplay.cpp) where we access the array of InlineLayoutInfo even though we might not have any inlined fields and only fields that are inlineable. I've changed this to use the normal "reference" path for fields that aren't flat.
Testing:
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/valhalla.git pull/1966/head:pull/1966$ git checkout pull/1966Update a local copy of the PR:
$ git checkout pull/1966$ git pull https://git.openjdk.org/valhalla.git pull/1966/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1966View PR using the GUI difftool:
$ git pr show -t 1966Using diff file
Download this PR as a diff file:
https://git.openjdk.org/valhalla/pull/1966.diff
Using Webrev
Link to Webrev Comment