Implement VM/GC support for JIT constant references#23257
Implement VM/GC support for JIT constant references#23257gacholio merged 2 commits intoeclipse-openj9:masterfrom
Conversation
|
@babsingh / @TobiAjila and @dmitripivkine / @amicic Requesting review of the VM and GC changes. |
dmitripivkine
left a comment
There was a problem hiding this comment.
GC part of the change looks good to me
| #endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ | ||
| , _valueTypesIterator(clazz) | ||
| #if defined(J9VM_OPT_OPENJDK_METHODHANDLE) | ||
| , _constRefsIterator(clazz) |
There was a problem hiding this comment.
This can be moved after line 100 in the existing ifdef.
There was a problem hiding this comment.
The reason for this and other cases of multiple J9VM_OPT_OPENJDK_METHODHANDLE ifdef blocks is due to -Werror,-Wreorder-ctor used for GC build phase. This will require some reordering of member declarations as well.
| GC_ClassStaticsIterator _classStaticsIterator; | ||
| GC_ConstantPoolObjectSlotIterator _constantPoolObjectSlotIterator; | ||
| GC_CallSitesIterator _callSitesIterator; | ||
| GC_MethodTypesIterator _methodTypesIterator; |
There was a problem hiding this comment.
Unrelated to this PR. Probably an oversight, but this and all other associated code can be placed under the J9VM_OPT_OPENJDK_METHODHANDLE ifdef.
There was a problem hiding this comment.
These fields are required in non-OpenJDK MH cases as well. In the case of _methodTypesIterator, there are two ways it is initialized based on the MH implementation:
OpenJDK MH:
OpenJ9 MH:
| #endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ | ||
| , _valueTypesIterator(clazz) | ||
| #if defined(J9VM_OPT_OPENJDK_METHODHANDLE) | ||
| , _constRefsIterator(clazz) |
There was a problem hiding this comment.
This can be moved after line 110 in the existing ifdef.
There was a problem hiding this comment.
Same explanation #23257 (comment)
Please let me know if I should proceed with changing the member declaration order as necessary to be able to have a single OpenJDK MH ifdef block.
Constant references will be analyzed by the JIT compiler at compile time
and each one will be attributed to an owning class. The slots will be
embedded in the JIT body for which they're needed. A run of one or more
slots owned by the same class will be described by a J9ConstRefArray,
which will be attached to the class in a circular doubly-linked list
(J9Class::constRefArrays, J9ConstRefArray::{prev,next}InClass).
Additionally, every J9ConstRefArray for a particular JIT body will be
part of a circular singly-linked list for the JIT body metadata
(J9JITExceptionTable::constRefArrays, J9ConstRefArray::nextInJITBody)
so that they can be destroyed in case of code cache reclamation.
There is a single global mutex that protects the J9ConstRefArray pool
and all of the linked list structures.
From a GC perspective, constant references will appear to be additional
static slots in the class that owns them.
This commit consists only of the changes needed outside of the JIT
compiler. Some context about the JIT part that is coming separately:
- At the end of a compilation that needs constant references, the JIT
compiler will allocate the needed J9ConstRefArray instances, and add
them into the appropriate lists.
- J9Class::constRefArrays will point to a sentinel entry rather than to
an entry that contains actual constant references. This is done to
simplify deletion and to avoid needing to add a pointer from each
J9ConstRefArray directly to its owning J9Class. The sentinel will be
allocated by the JIT compiler.
- To reduce overhead and simplify scanning, the GC scans the constant
references owned by a class without acquiring the mutex, so it will be
possible for the GC to be scanning the list for a class while the JIT
is adding to it. The JIT will use a memory barrier to make the
addition atomic w.r.t. any concurrent GC scanning.
- The JIT will initialize the slots using a write barrier so that the GC
can respond appropriately to the new slots. For example, the GC may
need to re-scan the class if the slots were initialized during
concurrent marking. As another example, in gencon the GC may need to
add the class object to the remembered set if any of the slots happens
to point to an object that's still in the nursery.
- The JIT will avoid calling the write barrier before the GC has been
made aware of the slots, i.e. before the J9ConstRefArray has been
added to the per-class list. So the full sequence for initializing
constant references on the JIT side will be as follows (though note
that step 4 is atomic w.r.t. GC scanning, as mentioned above):
1. Allocate the slots in the JIT body (during code generation).
2. Zero-initialize all of the slots.
3. Acquire the constant references mutex.
4. Set up the J9ConstRefArray(s) and add to all applicable lists.
5. Release the constant references mutex.
6. Acquire VM access.
7. Initialize the slots to their correct values via write barrier.
8. Release VM access.
- Because the GC scans without the mutex, it is not sufficient to hold
the mutex in order to destroy a J9ConstRefArray. It's also necessary
to know that no concurrent scanning is ongoing. This is the case
during class unloading and code cache reclamation (which will be part
of the upcoming JIT changes). It will also be necessary to destroy
J9ConstRefArrays on compilation failure in the unlikely event that
compilation fails after one or more J9ConstRefArrays have already been
successfully created for the JIT body. In that case, the JIT will
acquire exclusive VM access to allow for the necessary cleanup.
In ConstRefsIterator, moving JIT write protection toggling from the constructor/destructor to nextSlot() function reduces the duration that JIT write protection remains in disabled state. With this, omrthread_jit_write_protect_disable() is only called the first time nextSlot() is called for a non-empty set of constant reference slots. _jitWriteProtectDisabled field is used to keep track of the state of JIT write protection. When nextSlot() is to return NULL (empty list, or iteration reached the last slot), omrthread_jit_write_protect_enable() is called based on whether JIT write protection is in disabled state or not. Also includes some minor fixes based on review comments. Signed-off-by: Nazim Bhuiyan <nubhuiyan@ibm.com>
64bbd8a to
556bac0
Compare
|
jenkins test sanity zlinux jdk25 |
|
jenkins compile win jdk8 |
|
JDK25 sanity.openjdk test failures on zLinux: For this failure, see explanation in #23304 (comment). This failure is unrelated to the changes in this PR. |
This PR contributes @jdmpapin's work implementing the necessary VM and GC support for const refs. Please refer to the commit message for a detailed description.
Issue: #16616