RFR 8165246: [REDO] InstanceKlass::_previous_version_count goes negative
Coleen Phillimore
coleen.phillimore at oracle.com
Wed Sep 7 16:42:58 UTC 2016
On 9/7/16 11:36 AM, Daniel D. Daugherty wrote:
> On 9/6/16 10:24 AM, Coleen Phillimore wrote:
>> Summary: make _has_previous_version a boolean that is set to true
>> when previous version of a class is added or during class unloading
>> call to purge_previous_versions
>>
>> The failed fix was because InstanceKlass's previous_versions klasses
>> were walked more than once during class unloading, because the
>> scratch classes are also on the CLD::_klasses list. This change does
>> three things. 1. Only walk the class if has_been_redefined (which is
>> not set for the scratch class), 2. set next link to NULL for the
>> scratch class when removed from the previous version list, and 3.
>> change the counter to a flag because the counter may never go to zero
>> if a CLD has redefined classes with previous versions and is
>> unloaded. For this latter case we don't need to walk previous_versions.
>>
>> I tested this with changes 1 and 2 in Kitchensink, to verify the
>> diagnosis, and then added 3 and retested.
>> Also tested with the fix for
>> https://bugs.openjdk.java.net/browse/JDK-8156137 which was checked
>> into hs_-omp repository.
>>
>> Also ran through RBT 4 tiers nightly tests.
>>
>> open webrev at http://cr.openjdk.java.net/~coleenp/8165246.01/webrev
>
> src/share/vm/oops/instanceKlass.hpp
> No comments.
>
> src/share/vm/oops/instanceKlass.cpp
> L3370: // Globally, there is at least one previous version of a
> class to walk
> L3371: // during class unloading, which is saved because there are
> old methods in the class
> L3372: // are still running. Otherwise the previous version list
> is cleaned up.
> Perhaps a little tweaking of the comment:
>
> // Globally, there is at least one previous version of the
> class to walk
> // during class unloading, which was saved because there
> were old methods
> // in the class that are still running. Otherwise the
> previous version
> // list is cleaned up.
George had the same comment, so I fixed the grammar there.
>
> L3375: // Returns whether there are previous versions of a class
> for class
> L3376: // unloading only. This resets the value to false.
> purge_previous_versions
> L3377: // will set it to true if there are any left, i.e. if
> there's any work to do for
> L3378: // next time. This is to avoid the expensive code cache
> walk in CLDG::do_unloading.
> Perhaps a little tweaking of the comment:
>
> // Returns true if there are previous versions of a class
> for class
> // unloading only. Also resets the flag to false.
> purge_previous_versions
> // will set the flag to true if there are any left, i.e.,
> if there's any
> // work to do for next time. This is to avoid the expensive
> code cache
> // walk in CLDG::do_unloading().
>
Duly tweaked. I also renamed the function
has_previous_versions_and_reset().
> L3379: bool InstanceKlass::has_previous_versions() {
> L3383: _has_previous_versions = false;
> Named like a query function, but it has a side effect.
> Perhaps: has_previous_versions_and_reset()?
>
> L3391: assert (has_been_redefined(), "Should only be called for
> main class");
> Nit: please delete the space before '('.
>
Fixed.
> L3427: loader_data->add_to_deallocate_list(pv_node);
> L3428: InstanceKlass* next = pv_node->previous_versions();
> L3429: pv_node->link_previous_versions(NULL); // point
> next to NULL
> L3430: last->link_previous_versions(next);
> The pv_node to be deleted is added to the deallocate list
> before it is decoupled from chain. Perhaps it should be
> added after it is decoupled to permit parallel processing
> of the deallocate list, i.e., move L3427 after L3430. I
> don't think it is processed in parallel now, but down the
> road...
Okay, this seems like a good suggestion. It's not processed in parallel
now but yeah, you never know.
I did this carefully and added a comment.
log_trace(redefine, class, iklass, purge)
("previous version " INTPTR_FORMAT " is dead.", p2i(pv_node));
// For debugging purposes.
pv_node->set_is_scratch_class();
// Unlink from previous version list.
assert(pv_node->class_loader_data() == loader_data, "wrong
loader_data");
InstanceKlass* next = pv_node->previous_versions();
pv_node->link_previous_versions(NULL); // point next to NULL
last->link_previous_versions(next);
// Add to the deallocate list after unlinking.
loader_data->add_to_deallocate_list(pv_node);
pv_node = next;
deleted_count++;
version++;
>
> L3592: // Add previous version if any methods are still running.
> L3593: _has_previous_versions = true;
> In the other place you set the flag to true, you mention
> that this is for class unloading. Do you want to say that
> here also?
ok, added:
// Set has_previous_version flag for processing during class unloading.
>
>
> test/runtime/RedefineTests/RedefinePreviousVersions.java
> L26: * @bug 8164692
> Please change the bug ID to 8165246.
thanks, missed that.
>
> L27: * @summary Redefine previous_versions count goes negative
> Need to update the test summary.
* @summary Test has_previous_versions flag and processing during class
unloading.
>
> L88: // previous_version_list and the count should stay
> zero and not go negative
> Need to update the comment since there is no longer
> a counter.
// previous_version_list and the flag _has_previous_versions
should stay false
I reused the test so missed the old comments. Thanks for pointing them out.
>
> OK so the whole reason for InstanceKlass::has_previous_versions() is
> an optimization so that we don't have to do an expensive code cache
> walk for previous versions during class unloading. The old code
> implemented the "state of having a previous version" as a counter.
> The new code implements the "state of having a previous version"
> as a flag that is only set when we add a previous version (yea!)
> and cleared when it is queried. Since there is no more counter,
> we won't run into the bug we're trying to fix.
>
> The only thing that bugs me is this:
>
> bool v1 = has_previous_versions();
> bool v2 = has_previous_versions();
>
> I would expect (v1 == v2) which isn't what you get.
> Perhaps renaming from has_previous_versions() to
> has_previous_versions_and_reset() will make it clear
> that there is a side effect...
>
Yes, this is a bit dangerous to assume that two calls to
has_previuos_verisons() would have the same result. I renamed the
function as suggested.
Thanks for the thorough review!
Coleen
> Dan
>
>
>> bug link https://bugs.openjdk.java.net/browse/JDK-8165246
>>
>> Thanks,
>> Coleen
>>
>>
>
More information about the hotspot-runtime-dev
mailing list