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
8275731: CDS archived enums objects are recreated at runtime #6653
Conversation
|
/label add core-libs |
@iklam |
Webrevs
|
Mailing list message from Ioi Lam on hotspot-dev: Still looking for reviewers .... Thanks On 12/1/21 1:02 PM, Ioi Lam wrote: |
I don't really know this code well enough to do a good code review. I had some comments though.
@@ -377,6 +479,7 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions, | |||
log_info(cds)("Dumping objects to open archive heap region ..."); | |||
copy_open_objects(open_regions); | |||
|
|||
CDSHeapVerifier::verify(); |
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.
Should all this be DEBUG_ONLY ?
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 changed CDSHeapVerifier::verify() to a NOT_DEBUG_RETURN function.
KlassSubGraphInfo* _subgraph_info; | ||
oop _referrer; | ||
oop _obj; | ||
CachedOopInfo() :_subgraph_info(), _referrer(), _obj() {} |
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.
Should these be initialized to nullptr? does this do this?
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 three fields are initialized with the default initializer (empty parenthesis) so they will be initialized to the null pointer.
} | ||
|
||
ResourceMark rm; | ||
for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { |
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 this call instead
void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAPS), Handle mirror, TRAPS) {
and have this next few lines in 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.
I moved the code inside a new class CDSHeapVerifier::CheckStaticFields so I can call InstanceKlass::do_local_static_fields
if (k->is_instance_klass()) { | ||
InstanceKlass* ik = InstanceKlass::cast(k); | ||
for (JavaFieldStream fs(ik); !fs.done(); fs.next()) { | ||
if (!fs.access_flags().is_static()) { |
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.
same here. It only saves a couple of lines but then you can have the function outside this large 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.
You actually found a bug here. I am iterating over non-static fields and should walk the inherited fields as well. I changed the code to call InstanceKlass::do_nonstatic_fields()
ResourceObj::C_HEAP, | ||
mtClassShared, | ||
HeapShared::oop_hash> _table; | ||
|
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 this only used inside cdsHeapVerifier? if so it should be in the .cpp file. There's also an ArchiveableStaticFieldInfo. Not sure how they are related.
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 _table
is part of the CDSHeapVerifier instance, which is stack allocated. So I need to declare it as part of the CDSHeapVerifier class declaration in the hpp file.
|
||
oop mirror = k->java_mirror(); | ||
int i = 0; | ||
for (JavaFieldStream fs(k); !fs.done(); fs.next()) { |
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 seems like it should also use InstanceKlass::do_local_static_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.
Converting this to InstanceKlass::do_nonstatic_fields() is difficult because the loop body references 7 different variables declared outside of the loop.
One thing I tried is to add a new version of do_nonstatic_fields2() that supports C++ lambdas. You can see my experiment from here:
I changed all my new code to use the do_nonstatic_fields2() function with lambda.
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.
Ok, if it requires lambdas and additional change, never mind then.
@iklam this pull request can not be integrated into git checkout 8275731-heapshared-enum
git fetch https://git.openjdk.java.net/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
Hi Coleen, thanks for taking a look. This PR has two major parts:
Could you check if (2) is correct? |
@iklam 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! |
keepalive |
// | ||
// class Bar { | ||
// // this field is initialized in both CDS dump time and runtime. | ||
// static final Bar bar = new Bar; |
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.
new Bar
should be new Bar()
?
Looks good. Minor comment below.
Also, several files with copyright year 2021 need updating.
@iklam This change now passes all automated pre-integration checks. 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
|
Sorry for the long delay. It's a big change, but a lot in debug so that's ok. Looks good.
|
||
oop mirror = k->java_mirror(); | ||
int i = 0; | ||
for (JavaFieldStream fs(k); !fs.done(); fs.next()) { |
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.
Ok, if it requires lambdas and additional change, never mind then.
Thanks @calvinccheung and @coleenp for the review. Passed tiers 1-5. |
Going to push as commit d983d10.
Your commit was automatically rebased without conflicts. |
Background:
In the Java Language, Enums can be tested for equality, so the constants in an Enum type must be unique. Javac compiles an enum declaration like this:
to
With CDS archived heap objects,
Day::<clinit>
is executed twice: once duringjava -Xshare:dump
, and once during normal JVM execution. If the archived heap objects references one of the Enum constants created at dump time, we will violate the uniqueness requirements of the Enum constants at runtime. See the test case in the description of JDK-8275731Fix:
During -Xshare:dump, if we discovered that an Enum constant of type X is archived, we archive all constants of type X. At Runtime, type X will skip the normal execution of
X::<clinit>
. Instead, we runHeapShared::initialize_enum_klass()
to retrieve all the constants of X that were saved at dump time.This is safe as we know that
X::<clinit>
has no observable side effect -- it only creates the constants of type X, as well as the synthetic valueX::$VALUES
, which cannot be observed until X is fully initialized.Verification:
To avoid future problems, I added a new tool, CDSHeapVerifier, to look for similar problems where the archived heap objects reference a static field that may be recreated at runtime. There are some manual steps involved, but I analyzed the potential problems found by the tool are they are all safe (after the current bug is fixed). See cdsHeapVerifier.cpp for gory details. An example trace of this tool can be found at https://bugs.openjdk.java.net/secure/attachment/97242/enum_warning.txt
Testing:
Passed Oracle CI tiers 1-4. WIll run tier 5 as well.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/6653/head:pull/6653
$ git checkout pull/6653
Update a local copy of the PR:
$ git checkout pull/6653
$ git pull https://git.openjdk.java.net/jdk pull/6653/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 6653
View PR using the GUI difftool:
$ git pr show -t 6653
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/6653.diff