-
Notifications
You must be signed in to change notification settings - Fork 5.8k
8261090: Store old classfiles in static CDS archive #3479
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
8261090: Store old classfiles in static CDS archive #3479
Conversation
/label add hotspot-runtime |
👋 Welcome back ccheung! A progress list of the required criteria for merging this PR into |
@calvinccheung |
@calvinccheung The |
Webrevs
|
@@ -733,7 +756,7 @@ bool MetaspaceShared::try_link_class(Thread* current, InstanceKlass* ik) { | |||
ExceptionMark em(current); | |||
Thread* THREAD = current; // For exception macros. | |||
Arguments::assert_is_dumping_archive(); | |||
if (ik->is_loaded() && !ik->is_linked() && | |||
if (ik->is_loaded() && !ik->is_linked() && !MetaspaceShared::is_old_class(ik) && |
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 would be desirable to support the cases when verification is not enabled, which are not rare. For old classes, bytecode rewriting and class linking can still be done at dump time in those cases, with your current proposed change that includes old classes in the archive image. Otherwise, runtime would have to spend CPU cycles to do rewriting/linking for old classes when not truly necessary.
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 that should be done in a separate RFE. It has security implication -- it may not be a good idea to implement a performance feature that you can get only by disabling verification. This will need more community input and security review.
What we have implemented in this PR is a compromise -- support old classes in CDS as much as we can, without breaking any security mechanisms.
There are also alternatives for further improvement. For example, we can modify the old verifier to store verification constraints in the CDS archive. This will require more work, but will preserve the Java security model.
Could you please provide performance numbers? It would be good to understand the performance benefits from archiving the old classes when verification and linking are deferred at runtime. Thanks. |
I've added some performance numbers in the bug report. |
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. Some suggestions for comments and performance improvement.
@@ -284,8 +285,10 @@ bool Verifier::is_eligible_for_verification(InstanceKlass* klass, bool should_ve | |||
// Can not verify the bytecodes for shared classes because they have | |||
// already been rewritten to contain constant pool cache indices, | |||
// which the verifier can't understand. | |||
// Bytecodes for shared old classes can be verified because they have | |||
// not been rewritten. |
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.
Maybe put the above 2 lines under line 290, and change "can be" to "should be"?
// However, bytecodes for shared old classes should be verified because they have
// not been rewritten.
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.
Fixed.
if (!DumpSharedSpaces) { | ||
assert(!klass->is_shared(), "archive methods must not be rewritten at run time"); | ||
if (klass->is_shared()) { | ||
assert(!klass->is_rewritten(), "rewritten shared classes cannot be rewritten again"); |
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 add
assert(MetaspaceShared::is_old_class(klass), "only shared old classes aren't rewritten");
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.
Fixed.
@@ -138,7 +138,11 @@ void ConstantPool::metaspace_pointers_do(MetaspaceClosure* it) { | |||
log_trace(cds)("Iter(ConstantPool): %p", this); | |||
|
|||
it->push(&_tags, MetaspaceClosure::_writable); | |||
it->push(&_cache); | |||
if (!pool_holder()->is_rewritten()) { | |||
it->push(&_cache, MetaspaceClosure::_writable); |
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 shouldn't be necessary. All ConstantPoolCache are allocated in RW space by default.
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.
Fixed.
@@ -51,7 +51,7 @@ inline InstanceKlass* klassVtable::ik() const { | |||
} | |||
|
|||
bool klassVtable::is_preinitialized_vtable() { | |||
return _klass->is_shared() && !MetaspaceShared::remapped_readwrite(); | |||
return _klass->is_shared() && !MetaspaceShared::remapped_readwrite() && !MetaspaceShared::is_old_class(ik()); |
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.
Maybe we can avoid calling MetaspaceShared::is_old_class()
by adding an extra bit into klass.hpp:
#if INCLUDE_CDS
// Flags of the current shared class.
u2 _shared_class_flags;
enum {
_archived_lambda_proxy_is_available = 2,
_has_value_based_class_annotation = 4,
+ _is_shared_old_klass = 8
};
#endif
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 added the bit and it will be set in MetaspaceShared::linking_required
.
Also replaced calling MetaspaceShared::is_old_class()
with k->is_shared_old_klass()
in several places.
Thanks for your review.
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.
LGTM
@calvinccheung 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 73 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 |
!klass->is_shared() && | ||
// However, bytecodes for shared old classes can be verified because | ||
// they have not been rewritten. | ||
(!(klass->is_shared() && klass->is_rewritten())) && |
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 outmost brackets are not necessary. Could your remove 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.
Fixed. I also removed the extra include of metaspaceShared.hpp.
// create archive with class list | ||
OutputAnalyzer output = TestCommon.dump(appJar, appClasses, "-Xlog:class+load,cds=debug,verification=trace"); | ||
TestCommon.checkExecReturn(output, 0, | ||
dynamicMode ? true : 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.
Why use a ternary operator, is it the variable itself OK 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 prefer to leave it as is because the third arg to TestCommon.checkExecReturn()
is about whether or not to look for the strings in the subsequent args.
Thanks for your review.
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.
LGTM, only small nits.
…tag to new tests
/integrate |
@calvinccheung Since your change was applied there have been 84 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit 9499175. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Please review this RFE for storing old classfiles with major version < 50 in static CDS archive.
During static CDS dump time, old classes won't be verified/rewritten. They will be verified/rewritten during runtime.
Therefore, the
_constMethod
,_constants
, and_cache
of old classes must be stored in the RW region of the archive for runtime rewriting. TheConstantPool::remove_unshareable_info
will be skipped during dump time and theConstantPool::restore_unshareable_info
will be skipped during runtime for old classes.Passed tiers 1,2,3,4 tests on mach5.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/3479/head:pull/3479
$ git checkout pull/3479
Update a local copy of the PR:
$ git checkout pull/3479
$ git pull https://git.openjdk.java.net/jdk pull/3479/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 3479
View PR using the GUI difftool:
$ git pr show -t 3479
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/3479.diff