RFR: 8338379: Accesses to class init state should be properly synchronized
David Holmes
dholmes at openjdk.org
Mon Sep 23 01:51:41 UTC 2024
On Fri, 20 Sep 2024 14:02:51 GMT, Aleksey Shipilev <shade at openjdk.org> wrote:
> See the bug for the discussion. We have not seen a clear evidence this is _the_ problem in the field, neither we were able to come up with a reproducer. We have found this gap by inspecting the code, while chasing a production bug.
>
> In short, `InstanceKlass::_init_state` is used as the "witness" for initialized class state. When class initialization completes, it needs to publish the class state by writing `_init_state = _fully_initialized` with release semantics. Current patch makes a seqcst write, which is stronger than strictly necessary. I think it is okay to be extra paranoid on rarely-executed class initialization path.
>
> Various accessors that poll `IK::_init_state`, looking for class initialization to complete, need to read the field with acquire semantics. This is where the change fans out, touching VM, interpreter and compiler paths that e.g. implement clinit barriers. In some cases in assembler code, we can rely on hardware memory model to do what we need (i.e. acquire barriers/fences are nops).
>
> I made the best _guess_ what ARM32, S390X, PPC64, RISC-V code should look like, based on what related code does for volatile loads. It would be good if port maintainers could sanity-check those.
>
> Additional testing:
> - [x] Linux x86_64 server fastdebug, `all`
> - [x] Linux AArch64 server fastdebug, `all`
> - [x] GHA to test platform buildability + adhoc platform cross-compilation
Seems far more extensive than what was discussed. Code that takes the lock-free path to check `in_initialized` is what I thought we agreed needed the acquire/release not every read of the state variable. This code will be executed a lot and in 99.99% of cases the memory barriers are not needed.
src/hotspot/share/oops/instanceKlass.cpp line 4099:
> 4097: #endif
> 4098: assert(_init_thread == nullptr, "should be cleared before state change");
> 4099: Atomic::release_store_fence(&_init_state, state);
Why not just a release_store ?? Why do we need the trailing fence?
-------------
PR Review: https://git.openjdk.org/jdk/pull/21110#pullrequestreview-2321028771
PR Review Comment: https://git.openjdk.org/jdk/pull/21110#discussion_r1770709316
More information about the hotspot-dev
mailing list