-
Notifications
You must be signed in to change notification settings - Fork 126
8370450: [lworld] Alternate implementation of the substitutability test method #1695
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
Conversation
|
👋 Welcome back fparain! A progress list of the required criteria for merging this PR into |
|
@fparain 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 4 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. ➡️ To integrate this PR with the above commit message to the |
|
@fparain this pull request can not be integrated into git checkout new_acmp
git fetch https://git.openjdk.org/valhalla.git lworld
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge lworld"
git push |
Webrevs
|
| // Acmp map required for abstract and concrete value classes | ||
| FieldInfo::FieldFlags fflags2(0); | ||
| fflags2.update_injected(true); | ||
| fflags2.update_stable(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.
If c2 can model the field map read as a stable array read, this allows ValueObjectMethods to generate efficient code for specialized value types in the future. 👍
| "Minimal number of elements in a sorted collection to prefer" \ | ||
| "binary search over simple linear search." ) \ | ||
| \ | ||
| product(bool, UseAltSubstitutabilityMethod, false, \ |
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.
We might need this flag on/off for core-libs tests in addition to runtime tests.
|
When comparing the oops, do they need some additional handling? |
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.
It's really great work. I have some questions and minor suggested changes.
| } | ||
| if (!access_flags().is_identity_class() && !access_flags().is_interface() | ||
| && _class_name != vmSymbols::java_lang_Object()) { | ||
| // Acmp map required for abstract and concrete value classes |
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.
Thank you for this comment. Explains why abstract classes are omitted from above.
| // The Pair<int,int> values in the nonoop_acmp_map represent <offset,size> segments of memory | ||
| _nonoop_acmp_map = new GrowableArray<Pair<int,int>>(); | ||
| _oop_acmp_map = new GrowableArray<int>(); | ||
| if (_is_empty_inline_class) return; |
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 not return first before allocating these GrowableArray in resource area?
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.
It streamlines the code in InstanceKlass::fill_instance_klass() by not having to handle the null map case.
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.
Okay. I can't decide if you need a comment to prevent someone from changing this to have the quick exit. I guess they'll get a crash for the null case.
|
|
||
| case LayoutRawBlock::REGULAR: | ||
| { | ||
| FieldInfo* fi = _field_info->adr_at(b->field_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.
Is there an assumption that the block field indexes are in ascending order?
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 not sure I understand the question.
LayoutRawBlocks represent the fields layout, they are chained in ascending offset order.
The field_index is the index in the FieldInfo array (from the class file) where this field is declared.
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, that was the question. I meant to ask if the offsets are in ascending order, so that makes the code to coalesce them simpler. Can you add a comment at 1367 that the field offsets are in ascending order and that makes reading this easier.
The recursion is handled in ValueObjectMethods.isSubstitutableAlt() line 1447, the oops are compare using an acmp bytecode which will recurse if both oops are non null and instances of the same value 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.
I had a couple of comments and a comment request.
| // ^ ^ | ||
| // | | | ||
| // --------------------- Pair of integer describing a segment of | ||
| // contiguous non-oop 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.
Thanks for the ascii art - very helpful.
| // The Pair<int,int> values in the nonoop_acmp_map represent <offset,size> segments of memory | ||
| _nonoop_acmp_map = new GrowableArray<Pair<int,int>>(); | ||
| _oop_acmp_map = new GrowableArray<int>(); | ||
| if (_is_empty_inline_class) return; |
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.
Okay. I can't decide if you need a comment to prevent someone from changing this to have the quick exit. I guess they'll get a crash for the null case.
|
|
||
| case LayoutRawBlock::REGULAR: | ||
| { | ||
| FieldInfo* fi = _field_info->adr_at(b->field_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.
Yes, that was the question. I meant to ask if the offsets are in ascending order, so that makes the code to coalesce them simpler. Can you add a comment at 1367 that the field offsets are in ascending order and that makes reading this easier.
| return last_idx; | ||
| } | ||
|
|
||
| static int insert_map_at_offset(GrowableArray<Pair<int,int>>* nonoop_map, GrowableArray<int>* oop_map, |
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 copies the contents of the maps from an inline class that's flattened into this class or a super class into the map for this class.
| return map->append(Pair<int,int>(offset, size)); | ||
| } | ||
| last_idx = last_idx == -1 ? 0 : last_idx; | ||
| int start = map->adr_at(last_idx)->first > offset ? 0 : last_idx; |
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.
last_idx is an optimization to try to prevent searching through the field map to find where to insert {offset,size} for the new entry. When would it not be ascending? super classes and inlined classes are inserted in order that they're found in the LayoutBlocks so wouldn't the offsets be ascending?
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.
You answered this in slack for me. Can you put this at the top of this function:
The insert_segment creates an ordered list of maps {offset, size} from the LayoutRawBlocks. LayoutRawBlocks are queued in ascending offset order, and are processed in this order. This allows the last_idx optimization which would be critical for classes with a huge number of fields.
But, this property is not required, and, if you look at the entire set of fields being processed, they might not all be processed by ascending offset order.
Inherited fields are inserted first, by copying them from the super-class, and then local fields are processed. It is possible to have local fields interleaved with super-class fields. So all fields are not necessarily processed in ascending offset order. The algorithm tries to do it, and optimizes the insertion when it is done that way, but it also handles cases where this is not the case.
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.
Comments have been added in FieldLayoutBuilder::generate_acmp_maps().
Let me know if the explanation is sufficient to clarify how the code works.
| // last_idx remembers the position of the last insertion in order to speed up the next insertion. | ||
| // Local fields are processed in ascending offset order, so an insertion is very likely be performed | ||
| // next to the previous insertion. However, in some cases local fields and inherited fields can be | ||
| // interleaved, in which case the search of the insertion position cannot depend on the previous insertion. |
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.
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.
At the risk of repeating myself, this is great work!
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 library part looks acceptable, even though ideally I wish the VM would be able to request specialized comparison methods for each value type, so core library can provide specialized bytecode.
|
Coleen, Chen, Fred |
|
/integrate |
|
Going to push as commit 047e232.
Your commit was automatically rebased without conflicts. |
This is an alternate version of the substitutability method.
To use it, add -Xshare:off -XX:+UseAltSubstitutabilityMethod to the command line of the Valhalla VM in preview mode.
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/valhalla.git pull/1695/head:pull/1695$ git checkout pull/1695Update a local copy of the PR:
$ git checkout pull/1695$ git pull https://git.openjdk.org/valhalla.git pull/1695/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1695View PR using the GUI difftool:
$ git pr show -t 1695Using diff file
Download this PR as a diff file:
https://git.openjdk.org/valhalla/pull/1695.diff
Using Webrev
Link to Webrev Comment