|
27 | 27 | #include "classfile/javaClasses.hpp"
|
28 | 28 | #include "gc/shared/workerThread.hpp"
|
29 | 29 | #include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp"
|
| 30 | +#include "gc/shenandoah/shenandoahGeneration.hpp" |
30 | 31 | #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
|
31 | 32 | #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
|
32 | 33 | #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
|
@@ -58,17 +59,44 @@ static const char* reference_type_name(ReferenceType type) {
|
58 | 59 | }
|
59 | 60 | }
|
60 | 61 |
|
| 62 | +template <typename T> |
| 63 | +static void card_mark_barrier(T* field, oop value) { |
| 64 | + ShenandoahHeap* heap = ShenandoahHeap::heap(); |
| 65 | + assert(heap->is_in_or_null(value), "Should be in heap"); |
| 66 | + if (heap->mode()->is_generational() && heap->is_in_old(field) && heap->is_in_young(value)) { |
| 67 | + // We expect this to really be needed only during global collections. Young collections |
| 68 | + // discover j.l.r.Refs in the old generation during scanning of dirty cards |
| 69 | + // and these point to (as yet unmarked) referents in the young generation (see |
| 70 | + // ShenandoahReferenceProcessor::should_discover). Those cards will continue to |
| 71 | + // remain dirty on account of this cross-generational pointer to the referent. |
| 72 | + // Similarly, old collections will never discover j.l.r.Refs in the young generation. |
| 73 | + // It is only global collections that discover in both generations. Here we can |
| 74 | + // end up with a j.l.R in the old generation on the discovered list that |
| 75 | + // is not already on a dirty card, but which may here end up with a successor in |
| 76 | + // the discovered list that is in the young generation. This is the singular case |
| 77 | + // where the card needs to be dirtied here. We, however, skip the extra global'ness check |
| 78 | + // and always mark the card (redundantly during young collections). |
| 79 | + // The asserts below check the expected invariants based on the description above. |
| 80 | + assert(!heap->active_generation()->is_old(), "Expecting only young or global"); |
| 81 | + assert(heap->card_scan()->is_card_dirty(reinterpret_cast<HeapWord*>(field)) |
| 82 | + || heap->active_generation()->is_global(), "Expecting already dirty if young"); |
| 83 | + heap->card_scan()->mark_card_as_dirty(reinterpret_cast<HeapWord*>(field)); |
| 84 | + } |
| 85 | +} |
| 86 | + |
61 | 87 | template <typename T>
|
62 | 88 | static void set_oop_field(T* field, oop value);
|
63 | 89 |
|
64 | 90 | template <>
|
65 | 91 | void set_oop_field<oop>(oop* field, oop value) {
|
66 | 92 | *field = value;
|
| 93 | + card_mark_barrier(field, value); |
67 | 94 | }
|
68 | 95 |
|
69 | 96 | template <>
|
70 | 97 | void set_oop_field<narrowOop>(narrowOop* field, oop value) {
|
71 | 98 | *field = CompressedOops::encode(value);
|
| 99 | + card_mark_barrier(field, value); |
72 | 100 | }
|
73 | 101 |
|
74 | 102 | static oop lrb(oop obj) {
|
|
0 commit comments