RFR: 8075955: Replace the macro based implementation of oop_oop_iterate with a template based solution
Stefan Karlsson
stefan.karlsson at oracle.com
Thu Mar 26 16:35:23 UTC 2015
Hi,
Please review this patch to replace the macro based implementation of
oop_oop_iterate with a template based solution.
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/
https://bugs.openjdk.java.net/browse/JDK-8075955
Summary of the changes:
- Replace the macro implementation of the different oop_oop_iterate
functions with template functions. The implementation is moved out from
the *Klass.cpp files into the *Klass.inline.hpp files, to be able to
generate the specialized oop_oop_iterate functions in suitable GC
specific files.
See the old macro implementation:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceKlass.cpp.udiff.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceMirrorKlass.cpp.udiff.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceClassLoaderKlass.cpp.udiff.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceRefKlass.cpp.udiff.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/typeArrayKlass.cpp.udiff.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/objArrayKlass.cpp.udiff.html
That has now been converted into template functions:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceKlass.inline.hpp.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceMirrorKlass.inline.hpp.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceRefKlass.inline.hpp.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/typeArrayKlass.inline.hpp.html
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/objArrayKlass.inline.hpp.udiff.html
There's still a closure specialization layer implemented with macros to
support the code to allows the code to pass down the concrete closure
type, past the virtual Klass::oop_oop_iterate_nv(...) call. The macros
just calls the new template functions:
191 #define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType,
nv_suffix) \
192 int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj,
OopClosureType* closure) { \
193 return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj,
closure); \
194 }
We might want to remove this in a future patch, by providing our own
dispatch mechanism.
- Split the generation of the specialized oop_oop_iterate definitions,
so that we keep code from different GCs separated. Before this patch,
code from all GCs were generated into instanceKlass.cpp,
instanceMirrorKlass.cpp, instanceClassLoaderKlass.cpp,
instanceRefKlass.cpp, typeArrayKlass.cpp, and objArrayKlass.cpp.
Now the definitions are generated into:
G1:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/gc_implementation/g1/g1OopClosures.cpp.udiff.html
CMS:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.cpp.html
ParNew:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/gc_implementation/parNew/parOopClosures.cpp.html
Serial:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/memory/genOopClosures.cpp.html
- The other GCs don't use use the above mentioned closure
specialization, that is, they don't call obj->oop_iterate(&cl) to follow
the objects. Instead they have their own "visitor" functions located in
the oopDesc and *Klass classes. For example, Parallel Scavenge calls
obj->push_contents(...), which calls Klass::oop_push_contents(...), to
follow outgoing pointers after an object has been moved. These visitor
functions used to use the oop iterate macros and pass down snippets of
code to be applied to each oop*. This has now been changed to use use
closures and the new oop_oop_iterate template functions.
The implementation of these object visitor functions have been moved out
from the *Klass.cpp files and into the GCs that the functions support.
Using Parallel Scavenge as and example:
The implementation to handle the references out of a copied object was
located in:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceKlass.cpp.udiff.html
-void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
- InstanceKlass_OOP_MAP_REVERSE_ITERATE( \
- obj, \
- if (PSScavenge::should_scavenge(p)) { \
- pm->claim_or_forward_depth(p); \
- }, \
- assert_nothing )
-}
and has now been moved to:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp.udiff.html
+void InstanceKlass::oop_ps_push_contents(oop obj, PSPromotionManager* pm) {
+ PushContentsClosure cl(pm);
+ oop_oop_iterate_oop_maps_reverse<true>(obj, &cl);
+}
where the do_oop function is implemented as:
+
+ template <typename T> void do_oop_nv(T* p) {
+ if (PSScavenge::should_scavenge(p)) {
+ _pm->claim_or_forward_depth(p);
+ }
From the same file, it can be seen how that the implementation to
follow the references in the mirrors are using the same closure:
+void InstanceMirrorKlass::oop_ps_push_contents(oop obj,
PSPromotionManager* pm) {
...
+ InstanceKlass::oop_ps_push_contents(obj, pm);
+
+ PushContentsClosure cl(pm);
+ oop_oop_iterate_statics<true>(obj, &cl);
+}
As can be seen above, the functions are still members of the different
Klasses, but only the declaration is put in the klass.hpp files. The
actual implementation is put in the GC files. This helps decoupling the
different GCs and the Klasses. We could move the functions over to a GC
specific "visitor" and have a generic "accept" function in the Klasses,
but that approach would require two virtual calls, while the current
implementation only needs one.
In the future we might want to remove these functions from the *Klasses
and reuse the already existing code in the oop_oop_iterate framework.
If we take the InstanceMirrorKlass::oop_ps_push_contents function above
as an example, it could be implemented with
InstanceMirrorKlass::oop_oop_iterate, since they share the same structure:
54 template <bool nv, class OopClosureType>
55 int InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType*
closure) {
56 InstanceKlass::oop_oop_iterate<nv>(obj, closure);
57
58 if (Devirtualizer<nv>::do_metadata(closure)) {
59 Klass* klass = java_lang_Class::as_Klass(obj);
60 // We'll get NULL for primitive mirrors.
61 if (klass != NULL) {
62 Devirtualizer<nv>::do_klass(closure, klass);
63 }
64 }
65
66 oop_oop_iterate_statics<nv>(obj, closure);
67
68 return oop_size(obj);
69 }
Parallel Scavenge doesn't visit the klass pointers and do_metadata
returns false, so that code path will be eliminated by the compiler. We
would have to do something about the return oop_size(obj), since we
don't want to do that unnecessarily. To change the GC object visitors to
entirely use the oop_oop_iterator framework is out of scope for this patch.
The object visitor functions were renamed and moved as follows:
oop_follow_contents(opp) -> oop_ms_follow_contents(oop) in markSweep.cpp
oop_adjust_pointers(oop) -> oop_ms_adjust_pointers(oop) in markSweep.cpp
oop_follow_contents(oop, ParCompactionManager*) ->
oop_pc_follow_contents(...) in psCompactionManager.cpp
oop_update_pointers(oop) -> oop_pc_update_pointers(oop) in
psParallelCompact.cpp
oop_push_contents(oop, PSPromotionManager*) ->
oop_ps_push_contents(...) in psPromotionManager.cpp
- The oop iterate macros used to take an assert parameter to be applied
to oop* that were visited. By default, the check was
assert_is_in_closed_subset, but MS, PS and PC provided their own
asserts. ExtendedOopClosure has been handed the task to provide the
default verification, but also a way to turn it off for individual
closures, so that they can provide their own asserts. See:
ExtendedOopClosure::verify() and
ExtendedOopClosure::should_verify_oops() and how the Devirtualizer
dispatch class calls the verification code:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/memory/iterator.inline.hpp.udiff.html
+template <class OopClosureType, typename T>
+inline void Devirtualizer<true>::do_oop(OopClosureType* closure, T* p) {
+ debug_only(closure->verify(p));
+ closure->do_oop_nv(p);
+}
- Moved PSParallelCompact::MarkAndPushClosure::do_oop,
PSParallelCompact::AdjustPointerClosure::do_oop, mark_and_push, adjust
pointer, and follow_klass to psParallelCompact.inline.hpp
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp.udiff.html
- Add seemingly incorrect includes between GCs. This is needed since we
currently have no separation between GCs when we generate the
oop_since_save_marks_iterate functions. See:
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/memory/defNewGeneration.cpp.udiff.html
and the include of ParNew specific closures:
51 #if INCLUDE_ALL_GCS
52 #include "gc_implementation/parNew/parOopClosures.hpp"
53 #endif
which is needed to be able to generate:
856 ALL_SINCE_SAVE_MARKS_CLOSURES(DefNew_SINCE_SAVE_MARKS_DEFN)
This should be changed in a separate patch, so that DefNew only
generates oop_since_save_marks_iterate that takes DefNew specfic closures.
The initial performance runs showed a slight increase of the GC times on
some benchmarks on Solaris and Windows. The reason for this increase was
that the these compilers didn't inline as much as the hand-inlined
macros used to do. To remedy this I've increased the inlining in to ways:
- Turned on extra inlining for psPromotionManager.cpp when compiling
with the Solaris Studio Compiler
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/make/solaris/makefiles/product.make.udiff.html
- Added __forceinline to the InstanceKlass::oop_oop_iterate functions
when compiling with the MS compiler.
http://cr.openjdk.java.net/~stefank/8075955/webrev.01/src/share/vm/oops/instanceKlass.inline.hpp.html
A previous version of this patch has been run through our testing, but
I've recently done changes and extracted smaller patches, so I'll have
to rerun all testing.
Any requests for extra testing to be done?
Thanks,
StefanK
More information about the hotspot-dev
mailing list