RFR: 8245594: Remove volatile-qualified member functions and parameters from oop class
David Holmes
david.holmes at oracle.com
Sat May 23 13:30:25 UTC 2020
Hi Kim,
On 23/05/2020 5:04 am, Kim Barrett wrote:
>> On May 22, 2020, at 9:59 AM, David Holmes <david.holmes at oracle.com> wrote:
>>
>> On 22/05/2020 6:23 pm, Kim Barrett wrote:
>>>> On May 21, 2020, at 10:39 PM, David Holmes <david.holmes at oracle.com> wrote:
>>>>
>>>> On 22/05/2020 8:31 am, Kim Barrett wrote:
>>>>> Changed constructors for MemoryManager and MemoryPool to use
>>>>> initializer list, so we don't need to use Atomic::store to initialize
>>>>> an oop-derived member.
>>>>
>>>> What is the connection between using an initializer-list and not needing the Atomic::Store?
>>> The volatile oop-derived member (instanceOop in both cases) needs to
>>> be initialized. If done in an initializer list, it's at construction
>>> time for the member object, where volatile isn't relevant. If done
>>> later (for example, in the containing object's constructor body, the
>>> member is now volatile and so involved a volatile assignment, which
>>> would now need to be an Atomic::store.
>>
>> I still don't see any distinction there with regards to why we use volatile or equivalently Atomic::store.
>
> Here's an example.
>
> A sufficient smaller change to the MemoryManager constructor would have been
>
> 41 MemoryManager::MemoryManager(const char* name) : _name(name) {
> 42 _num_pools = 0;
> - 43 (void)const_cast<instanceOop&>(_memory_mgr_obj = instanceOop(NULL));
> + 43 Atomic::store(&_memory_manager, instanceOop(NULL));
> 44 }
>
> The old code doesn't compile without the volatile qualified oop::operator=.
>
> A different, but not good (as in invokes UB), way to address the compilation failure
>
> const_cast<instanceOop&>(_memory_mgr_obj) = instanceOop(NULL);
>
> Instead, I changed it to
>
> 41 MemoryManager::MemoryManager(const char* name) :
> 42 _num_pools(0), _name(name), _memory_mgr_obj() {}
>
> No Atomic store needed here.
This is missing the point. If Atomic::store is presumed necessary for
some kind of atomicity guarantee, then how does use of an initializer
list achieve the same requirement?
>>>>
>>>> In the following the referenced oops still retain their volatile qualifier - should it not now be removed?
>>>>
>>>> - src/hotspot/share/runtime/thread.hpp
>>>> _exception_oop is still marked volatile
>>>> - src/hotspot/share/services/memoryManager.hpp
>>>> _memory_mgr_obj is still marked volatile
>>>> - src/hotspot/share/services/memoryPool.hpp
>>>> _memory_pool_obj is still marked volatile
>>> Access to these objects is via Atomic operations, so they should still
>>> be volatile qualified per current convention.
>>
>> The current convention allows for naked loads and stores on volatile variables. When we only have Atomic load/store plus other atomic ops then the "convention" no longer requires the variable to be volatile. Which in turn would I assume undo the initializer-list argument.
>
> (See also my reply to Coleen in this thread.)
>
> The convention of volatile qualifying variables that we want to treat
> "atomically" only allows naked loads and stores for fundamental types,
> not for class types. The volatile qualifier for a member of type oop
> uses the compiler to help keep us honest, because naked loads and
> stores won't compile. (The same thing was done for markWord; JDK-8229838.)
Hmmm. Granted "volatile" on a Class type has no meaning. But I always
think of oop as really being a pointer type so volatile actually makes
some sense there.
By the same token Atomic::load/store have no meaning on class types either.
So now I'm very unsure what we are actually doing here ??
David
More information about the hotspot-dev
mailing list