On Tue, 3 Nov 2020 12:58:22 GMT, Coleen Phillimore <cole...@openjdk.org> wrote:

>> This change turns the HashTable that JVMTI uses for object tagging into a 
>> regular Hotspot hashtable - the one in hashtable.hpp with resizing and 
>> rehashing.   Instead of pointing directly to oops so that GC has to walk the 
>> table to follow oops and then to rehash the table, this table points to 
>> WeakHandle.  GC walks the backing OopStorages concurrently.
>> 
>> The hash function for the table is a hash of the lower 32 bits of the 
>> address.  A flag is set during GC (gc_notification if in a safepoint, and 
>> through a call to JvmtiTagMap::needs_processing()) so that the table is 
>> rehashed at the next use.
>> 
>> The gc_notification mechanism of weak oop processing is used to notify Jvmti 
>> to post ObjectFree events.  In concurrent GCs there can be a window of time 
>> between weak oop marking where the oop is unmarked, so dead (the phantom 
>> load in peek returns NULL) but the gc_notification hasn't been done yet.  In 
>> this window, a heap walk or GetObjectsWithTags call would not find an object 
>> before the ObjectFree event is posted.  This is dealt with in two ways:
>> 
>> 1. In the Heap walk, there's an unconditional table walk to post events if 
>> events are needed to post.
>> 2. For GetObjectWithTags, if a dead oop is found in the table and posting is 
>> required, we use the VM thread to post the event.
>> 
>> Event posting cannot be done in a JavaThread because the posting needs to be 
>> done while holding the table lock, so that the JvmtiEnv state doesn't change 
>> before posting is done.  ObjectFree callbacks are limited in what they can 
>> do as per the JVMTI Specification.  The allowed callbacks to the VM already 
>> have code to allow NonJava threads.
>> 
>> To avoid rehashing, I also tried to use object->identity_hash() but this 
>> breaks because entries can be added to the table during heapwalk, where the 
>> objects use marking.  The starting markWord is saved and restored.  Adding a 
>> hashcode during this operation makes restoring the former markWord (locked, 
>> inflated, etc) too complicated.  Plus we don't want all these objects to 
>> have hashcodes because locking operations after tagging would have to always 
>> use inflated locks.
>> 
>> Much of this change is to remove serial weak oop processing for the 
>> weakProcessor, ZGC and Shenandoah.  The GCs have been stress tested with 
>> jvmti code.
>> 
>> It has also been tested with tier1-6.
>> 
>> Thank you to Stefan, Erik and Kim for their help with this change.
>
> Coleen Phillimore has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   More review comments from Stefan and ErikO

src/hotspot/share/gc/shared/weakProcessorPhases.hpp line 41:

> 39:   class Iterator;
> 40: 
> 41:   typedef void (*Processor)(BoolObjectClosure*, OopClosure*);

I think this typedef is to support serial phases and that it is probably no 
longer used.

src/hotspot/share/gc/shared/weakProcessorPhases.hpp line 50:

> 48: };
> 49: 
> 50: typedef uint WeakProcessorPhase;

This was originally written with the idea that WeakProcessorPhases::Phase (and 
WeakProcessorPhase) should be a scoped enum (but we didn't have that feature 
yet). It's possible there are places that don't cope with a scoped enum, since 
that feature wasn't available when the code was written, so there might have be 
mistakes.

But because of that, I'd prefer to keep the WeakProcessorPhases::Phase type and 
the existing definition of WeakProcessorPhase. Except this proposed change is 
breaking that at least here:

src/hotspot/share/gc/shared/weakProcessor.inline.hpp
116     uint oopstorage_index = WeakProcessorPhases::oopstorage_index(phase);
117     StorageState* cur_state = _storage_states.par_state(oopstorage_index);
=>
103     StorageState* cur_state = _storage_states.par_state(phase);

I think eventually (as in some future RFE) this could all be collapsed to 
something provided by OopStorageSet.
enum class : uint WeakProcessorPhase {}; 

ENUMERATOR_RANGE(WeakProcessorPhase,
                 static_cast<WeakProcessorPhase>(0), 
                 static_cast<WeakProcessorPhase>(OopStorageSet::weak_count));
and replacing all uses of WeakProcessorPhases::Iterator with 
EnumIterator<WeakProcessorPhase> (which involves more than a type alias).

Though it might be possible to go even further and eliminate 
WeakProcessorPhases as a thing separate from OopStorageSet.

-------------

PR: https://git.openjdk.java.net/jdk/pull/967

Reply via email to