-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
8352536: Add overloads to parse and build class files from/to MemorySegment #24139
base: master
Are you sure you want to change the base?
Conversation
…fer and MemorySegment
/csr |
👋 Welcome back dmlloyd! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
Webrevs
|
src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java
Outdated
Show resolved
Hide resolved
@Override | ||
public ClassModel parse(final MemorySegment bytes) { | ||
AbstractMemorySegmentImpl amsi = (AbstractMemorySegmentImpl) bytes; | ||
if (amsi.unsafeGetBase() instanceof byte[] ba) { |
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 also MemorySegment::heapObject
if you don't want to drop down to unsafe. That method returns an empty optional if the segment is read-only -- but that might be good enough for a fast-path.
Class-File API passed through several significant weight reductions in its history (on the API surface as well as under the skin). Some of the steps were critical to avoid JDK bootstrap performance regression. Before deciding about this non-trivial addition to the Class-File API I would like to see some measurable benefits and performance impact on the JDK bootstrap. |
A simple test to run a program with a single lambda in it did not cause the Since the JDK code paths do not run through the new APIs, I would expect the only possible performance impact to come from the non-functional common code refactoring (extracting common methods) on the write side. So, I've run With patch:
Without patch:
It looks like they are all solidly within the margin of error. If there are any other tests you'd like me to run (or different parameters etc.) please let me know. If this all looks ok, @asotona could you please review the CSR? |
I'm sorry, but I'm still missing the benefits part of this change. The costs are high. The API grows, implementation splits into multiple parallel branches in ClassFileImpl and DirectClassBuilder. I'm not convinced the API should be extended with the MemorySegment overrides. |
The benefits are that the user can parse and generate class files directly from and to mapped files, and parse class files directly from buffers given to a class loader (for example). On the parsing side, there is an extra copy (this is not worse than today), but it is theoretically possible that we could optimize this someday. At absolute worst, it eliminates the need for the user to do this copy manually. On the generation side, there is no extra copy needed in comparison to the byte array implementation.
I'm not sure I follow you here. The implementation is only minimally changed. Half of the 419 lines added are javadocs. I'm not sure I understand where the new costs are coming from.
This is just a test class. It proves the functionality of the new API in terms of the existing API; this means that it is not necessary to retest all functionality for both input types.
It shouldn't; there is not a parallel implementation, and I think it's reasonable to at least make the argument that there should not be in the future either. Nothing here will force that issue one way or the other. As I said above, because there is still only one implementation, one test class is sufficient to show that parsing and generating to memory segments is working correctly.
All the
I hope you reconsider in light of the above explanations. Thanks! |
As the parsing benefits are none due to the memory copy. |
The main benefit on the parsing is twofold: reducing the user's boilerplate, and the future possibility of further optimizing this case. At present the performance is the same as making the user do the copy.
Sure, I can put together a benchmark which compares the throughput with and without the copy and maybe also compares the allocation rate. I hope that would be sufficient to capture whatever there is to capture. |
Here's the raw benchmark results against
Here is the same benchmark with
You can see that in addition to the overhead of copying, we also put a bit more pressure on the GC despite having similar numbers of allocations by filling up our allocation regions more quickly with the extra large array per operation, which requires a little more time to be spent in GC on average. We are allocating roughly the same number of objects in either case. |
I have two problems with the numbers you measured:
When I modify
So my measured performance benefit is around 1% and even that will vaporize when writing to physical files as inteded. Unfortunately I could not recommend this PR. |
Can you share your changes? |
If we want to reduce allocation at writing time, we may well look at the new allocation facility from #24232; that is a general-utility tool to reduce allocation pressure for large byte arrays, especially if an actual |
Provide method overloads to the ClassFile interface of the java.lang.classfile API which allow parsing of classes found in memory segments, as well as allowing built class files to be output to them.
Progress
Issues
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/24139/head:pull/24139
$ git checkout pull/24139
Update a local copy of the PR:
$ git checkout pull/24139
$ git pull https://git.openjdk.org/jdk.git pull/24139/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 24139
View PR using the GUI difftool:
$ git pr show -t 24139
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/24139.diff
Using Webrev
Link to Webrev Comment