-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8294961: Convert java.base/java.lang.reflect.ProxyGenerator to use the Classfile API to generate proxy classes #17121
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
…e Classfile API to generate proxy classes
|
👋 Welcome back asotona! A progress list of the required criteria for merging this PR into |
Webrevs
|
| PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(parameterTypes[i]); | ||
| cob.getstatic(prim.wrapperClass, "TYPE", CD_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.
These can use a condy via ConstantBootstraps::primitiveClass(MethodHandles.Lookup, String, Class<?>), although that’s probably gonna need JDK‑8283739.
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 recommend optimizing in another patch, as this patch aims to preserve code parity.
|
Can you explain the changes to resolve the performance regressions? |
|
Profiling of the benchmarks revealed several slowdowns:
Proposed performance improvements use pre-generated template class and each proxy is then transformed with share constant pool. Performance fixes related to ClassFile API Full benchmark numbers will be ready soon. |
|
Here are actual numbers (_22 is before this patch): |
src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java
Outdated
Show resolved
Hide resolved
| dcb.methodInfo.methodName().stringValue(), | ||
| dcb.methodInfo.methodTypeSymbol(), | ||
| dcb.methodInfo.methodName(), | ||
| dcb.methodInfo.methodType(), |
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.
Can you enlighten me on why this actually leads to a performance improvement? Don't we already generate the methods with MethodTypeDesc symbols in ProxyGenerator so that they should be cached?
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 code is part of the ClassFile API’s internals, and so it doesn’t have access to ProxyGenerator’s cached MethodTypeDescs, only the underlying Utf8Entry, so it’d need to be parsed.
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 now Class return type and Class array parameter types are directly converted to Strings instead of MTDs. I think that we should really run ProxyGenerator with JFR to profile and see the results (for instance, old ASM has a stackmap generation penalty due to parsing method descriptors on the fly compared to CF API, despite CF's slower overall performance due to allocations like Optional)
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.
These changes are based on profiling of the benchmarks.
StackCounter was not used in any performance critical applications and profiling revealed some obvious bottlenecks.
src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java
Outdated
Show resolved
Hide resolved
| dcb.methodInfo.methodName().stringValue(), | ||
| dcb.methodInfo.methodTypeSymbol(), | ||
| dcb.methodInfo.methodName(), | ||
| dcb.methodInfo.methodType(), |
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 code is part of the ClassFile API’s internals, and so it doesn’t have access to ProxyGenerator’s cached MethodTypeDescs, only the underlying Utf8Entry, so it’d need to be parsed.
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
…ounter.java Co-authored-by: ExE Boss <[email protected]>
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 it's okay to split the fix to SplitConstantPool.java and StackCounter.java in a separate PR now. This PR can go next once reviewed.
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
| generateConstructor(clb); | ||
| generateLookupAccessor(clb); | ||
| var cp = clb.constantPool(); | ||
| q.entries = new PoolEntry[] { |
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.
line 174-197 must match the order of CP entries being added.
Is there other way to avoid q.next() coupling with the order of CP entries in q.entries? Maybe define constants for the indices to q.entries such that writing and reading the CP entries from the array using the constant index is easier to read and less error-prone?
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've rewritten the initialization to use indexes inside an array.
Thanks.
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
Do you think these also cause the performance overhead in converting java.lang.invoke to use ClassFile API (#17108)? |
liach
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.
Also StackMapDecoder::initFrameFromLocals(ClassEntry, ...) can benefit from 2 changes:
- Iterate MTD by index instead of creating copies
- Pass ClassEntry from reader/writer constant pool to ObjectVerificationTypeInfoImpl instead of using the temporary pool
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
| for (var arg : mDesc.parameterList()) { | ||
| addStackSlot(-TypeKind.from(arg).slotSize()); | ||
| } | ||
| addStackSlot(-countMethodStack(nameAndType.type(), 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.
Can use something like:
var mtd = Util.methodTypeSymbol(nameAndType);
addStackSlot(Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd));if you stick with MTD.
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.
Calculation of MTD for each method invocation is extremely ineffective way to just count the size.
|
I've separated ClassFile API performance related improvements into |
Yes, I think it affects all performance critical applications. |
I'll add this fix to the performance improvements PR, thanks!
Unfortunately initi frame is implicit and the entries may not exist in the constant pool at all. |
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 change looks fine. Please rerun the benchmark after JDK-8323183 is integrated. I made JDK-8294961 blocked by JDK-8323183 to ensure it goes in after it.
src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java
Outdated
Show resolved
Hide resolved
|
@asotona 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 no new commits pushed to the ➡️ To integrate this PR with the above commit message to the |
Co-authored-by: Mandy Chung <[email protected]>
|
@asotona This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
|
/integrate |
|
Going to push as commit bee50cd.
Your commit was automatically rebased without conflicts. |
java.base java.lang.reflect.ProxyGenerator uses ASM to generate proxy classes.
This patch converts it to use Classfile API.
It is continuation of #10991
Any comments and suggestions are welcome.
Please review.
Thank you,
Adam
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/17121/head:pull/17121$ git checkout pull/17121Update a local copy of the PR:
$ git checkout pull/17121$ git pull https://git.openjdk.org/jdk.git pull/17121/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 17121View PR using the GUI difftool:
$ git pr show -t 17121Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/17121.diff
Webrev
Link to Webrev Comment