|
1 /* |
|
2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 #include "precompiled.hpp" |
|
26 #include "gc/shared/cardTableBarrierSet.inline.hpp" |
|
27 #include "gc/shared/collectedHeap.hpp" |
|
28 #include "gc/shared/genCollectedHeap.hpp" |
|
29 #include "gc/shared/space.inline.hpp" |
|
30 #include "logging/log.hpp" |
|
31 #include "memory/virtualspace.hpp" |
|
32 #include "oops/oop.inline.hpp" |
|
33 #include "runtime/thread.hpp" |
|
34 #include "services/memTracker.hpp" |
|
35 #include "utilities/align.hpp" |
|
36 #include "utilities/macros.hpp" |
|
37 |
|
38 // This kind of "BarrierSet" allows a "CollectedHeap" to detect and |
|
39 // enumerate ref fields that have been modified (since the last |
|
40 // enumeration.) |
|
41 |
|
42 CardTableBarrierSet::CardTableBarrierSet( |
|
43 CardTable* card_table, |
|
44 const BarrierSet::FakeRtti& fake_rtti) : |
|
45 ModRefBarrierSet(fake_rtti.add_tag(BarrierSet::CardTableBarrierSet)), |
|
46 _defer_initial_card_mark(false), |
|
47 _card_table(card_table) |
|
48 {} |
|
49 |
|
50 CardTableBarrierSet::CardTableBarrierSet(CardTable* card_table) : |
|
51 ModRefBarrierSet(BarrierSet::FakeRtti(BarrierSet::CardTableBarrierSet)), |
|
52 _defer_initial_card_mark(false), |
|
53 _card_table(card_table) |
|
54 {} |
|
55 |
|
56 void CardTableBarrierSet::initialize() { |
|
57 initialize_deferred_card_mark_barriers(); |
|
58 } |
|
59 |
|
60 CardTableBarrierSet::~CardTableBarrierSet() { |
|
61 delete _card_table; |
|
62 } |
|
63 |
|
64 void CardTableBarrierSet::write_ref_array_work(MemRegion mr) { |
|
65 _card_table->dirty_MemRegion(mr); |
|
66 } |
|
67 |
|
68 void CardTableBarrierSet::invalidate(MemRegion mr) { |
|
69 _card_table->invalidate(mr); |
|
70 } |
|
71 |
|
72 void CardTableBarrierSet::print_on(outputStream* st) const { |
|
73 _card_table->print_on(st); |
|
74 } |
|
75 |
|
76 // Helper for ReduceInitialCardMarks. For performance, |
|
77 // compiled code may elide card-marks for initializing stores |
|
78 // to a newly allocated object along the fast-path. We |
|
79 // compensate for such elided card-marks as follows: |
|
80 // (a) Generational, non-concurrent collectors, such as |
|
81 // GenCollectedHeap(ParNew,DefNew,Tenured) and |
|
82 // ParallelScavengeHeap(ParallelGC, ParallelOldGC) |
|
83 // need the card-mark if and only if the region is |
|
84 // in the old gen, and do not care if the card-mark |
|
85 // succeeds or precedes the initializing stores themselves, |
|
86 // so long as the card-mark is completed before the next |
|
87 // scavenge. For all these cases, we can do a card mark |
|
88 // at the point at which we do a slow path allocation |
|
89 // in the old gen, i.e. in this call. |
|
90 // (b) GenCollectedHeap(ConcurrentMarkSweepGeneration) requires |
|
91 // in addition that the card-mark for an old gen allocated |
|
92 // object strictly follow any associated initializing stores. |
|
93 // In these cases, the memRegion remembered below is |
|
94 // used to card-mark the entire region either just before the next |
|
95 // slow-path allocation by this thread or just before the next scavenge or |
|
96 // CMS-associated safepoint, whichever of these events happens first. |
|
97 // (The implicit assumption is that the object has been fully |
|
98 // initialized by this point, a fact that we assert when doing the |
|
99 // card-mark.) |
|
100 // (c) G1CollectedHeap(G1) uses two kinds of write barriers. When a |
|
101 // G1 concurrent marking is in progress an SATB (pre-write-)barrier |
|
102 // is used to remember the pre-value of any store. Initializing |
|
103 // stores will not need this barrier, so we need not worry about |
|
104 // compensating for the missing pre-barrier here. Turning now |
|
105 // to the post-barrier, we note that G1 needs a RS update barrier |
|
106 // which simply enqueues a (sequence of) dirty cards which may |
|
107 // optionally be refined by the concurrent update threads. Note |
|
108 // that this barrier need only be applied to a non-young write, |
|
109 // but, like in CMS, because of the presence of concurrent refinement |
|
110 // (much like CMS' precleaning), must strictly follow the oop-store. |
|
111 // Thus, using the same protocol for maintaining the intended |
|
112 // invariants turns out, serendepitously, to be the same for both |
|
113 // G1 and CMS. |
|
114 // |
|
115 // For any future collector, this code should be reexamined with |
|
116 // that specific collector in mind, and the documentation above suitably |
|
117 // extended and updated. |
|
118 void CardTableBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { |
|
119 #if defined(COMPILER2) || INCLUDE_JVMCI |
|
120 if (!ReduceInitialCardMarks) { |
|
121 return; |
|
122 } |
|
123 // If a previous card-mark was deferred, flush it now. |
|
124 flush_deferred_card_mark_barrier(thread); |
|
125 if (new_obj->is_typeArray() || _card_table->is_in_young(new_obj)) { |
|
126 // Arrays of non-references don't need a post-barrier. |
|
127 // The deferred_card_mark region should be empty |
|
128 // following the flush above. |
|
129 assert(thread->deferred_card_mark().is_empty(), "Error"); |
|
130 } else { |
|
131 MemRegion mr((HeapWord*)new_obj, new_obj->size()); |
|
132 assert(!mr.is_empty(), "Error"); |
|
133 if (_defer_initial_card_mark) { |
|
134 // Defer the card mark |
|
135 thread->set_deferred_card_mark(mr); |
|
136 } else { |
|
137 // Do the card mark |
|
138 invalidate(mr); |
|
139 } |
|
140 } |
|
141 #endif // COMPILER2 || JVMCI |
|
142 } |
|
143 |
|
144 void CardTableBarrierSet::initialize_deferred_card_mark_barriers() { |
|
145 // Used for ReduceInitialCardMarks (when COMPILER2 or JVMCI is used); |
|
146 // otherwise remains unused. |
|
147 #if defined(COMPILER2) || INCLUDE_JVMCI |
|
148 _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers() |
|
149 && (DeferInitialCardMark || card_mark_must_follow_store()); |
|
150 #else |
|
151 assert(_defer_initial_card_mark == false, "Who would set it?"); |
|
152 #endif |
|
153 } |
|
154 |
|
155 void CardTableBarrierSet::flush_deferred_card_mark_barrier(JavaThread* thread) { |
|
156 #if defined(COMPILER2) || INCLUDE_JVMCI |
|
157 MemRegion deferred = thread->deferred_card_mark(); |
|
158 if (!deferred.is_empty()) { |
|
159 assert(_defer_initial_card_mark, "Otherwise should be empty"); |
|
160 { |
|
161 // Verify that the storage points to a parsable object in heap |
|
162 DEBUG_ONLY(oop old_obj = oop(deferred.start());) |
|
163 assert(!_card_table->is_in_young(old_obj), |
|
164 "Else should have been filtered in on_slowpath_allocation_exit()"); |
|
165 assert(oopDesc::is_oop(old_obj, true), "Not an oop"); |
|
166 assert(deferred.word_size() == (size_t)(old_obj->size()), |
|
167 "Mismatch: multiple objects?"); |
|
168 } |
|
169 write_region(deferred); |
|
170 // "Clear" the deferred_card_mark field |
|
171 thread->set_deferred_card_mark(MemRegion()); |
|
172 } |
|
173 assert(thread->deferred_card_mark().is_empty(), "invariant"); |
|
174 #else |
|
175 assert(!_defer_initial_card_mark, "Should be false"); |
|
176 assert(thread->deferred_card_mark().is_empty(), "Should be empty"); |
|
177 #endif |
|
178 } |
|
179 |
|
180 void CardTableBarrierSet::on_thread_detach(JavaThread* thread) { |
|
181 // The deferred store barriers must all have been flushed to the |
|
182 // card-table (or other remembered set structure) before GC starts |
|
183 // processing the card-table (or other remembered set). |
|
184 flush_deferred_card_mark_barrier(thread); |
|
185 } |
|
186 |
|
187 bool CardTableBarrierSet::card_mark_must_follow_store() const { |
|
188 return _card_table->scanned_concurrently(); |
|
189 } |