Mercurial > hg > graal-compiler
annotate src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp @ 1091:6aa7255741f3
6906727: UseCompressedOops: some card-marking fixes related to object arrays
Summary: Introduced a new write_ref_array(HeapWords* start, size_t count) method that does the requisite MemRegion range calculation so (some of the) clients of the erstwhile write_ref_array(MemRegion mr) do not need to worry. This removed all external uses of array_size(), which was also simplified and made private. Asserts were added to catch other possible issues. Further, less essential, fixes stemming from this investigation are deferred to CR 6904516 (to follow shortly in hs17).
Reviewed-by: kvn, coleenp, jmasa
author | ysr |
---|---|
date | Thu, 03 Dec 2009 15:01:57 -0800 |
parents | 0fbdb4381b99 |
children | c18cbe5936b8 |
rev | line source |
---|---|
0 | 1 /* |
579 | 2 * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. |
0 | 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_psMarkSweepDecorator.cpp.incl" | |
27 | |
28 PSMarkSweepDecorator* PSMarkSweepDecorator::_destination_decorator = NULL; | |
29 | |
30 | |
31 void PSMarkSweepDecorator::set_destination_decorator_tenured() { | |
32 ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); | |
33 assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); | |
34 | |
35 _destination_decorator = heap->old_gen()->object_mark_sweep(); | |
36 } | |
37 | |
38 void PSMarkSweepDecorator::set_destination_decorator_perm_gen() { | |
39 ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); | |
40 assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); | |
41 | |
42 _destination_decorator = heap->perm_gen()->object_mark_sweep(); | |
43 } | |
44 | |
45 void PSMarkSweepDecorator::advance_destination_decorator() { | |
46 ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); | |
47 assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); | |
48 | |
49 assert(_destination_decorator != NULL, "Sanity"); | |
50 guarantee(_destination_decorator != heap->perm_gen()->object_mark_sweep(), "Cannot advance perm gen decorator"); | |
51 | |
52 PSMarkSweepDecorator* first = heap->old_gen()->object_mark_sweep(); | |
53 PSMarkSweepDecorator* second = heap->young_gen()->eden_mark_sweep(); | |
54 PSMarkSweepDecorator* third = heap->young_gen()->from_mark_sweep(); | |
55 PSMarkSweepDecorator* fourth = heap->young_gen()->to_mark_sweep(); | |
56 | |
57 if ( _destination_decorator == first ) { | |
58 _destination_decorator = second; | |
59 } else if ( _destination_decorator == second ) { | |
60 _destination_decorator = third; | |
61 } else if ( _destination_decorator == third ) { | |
62 _destination_decorator = fourth; | |
63 } else { | |
64 fatal("PSMarkSweep attempting to advance past last compaction area"); | |
65 } | |
66 } | |
67 | |
68 PSMarkSweepDecorator* PSMarkSweepDecorator::destination_decorator() { | |
69 assert(_destination_decorator != NULL, "Sanity"); | |
70 | |
71 return _destination_decorator; | |
72 } | |
73 | |
74 // FIX ME FIX ME FIX ME FIX ME!!!!!!!!! | |
75 // The object forwarding code is duplicated. Factor this out!!!!! | |
76 // | |
77 // This method "precompacts" objects inside its space to dest. It places forwarding | |
78 // pointers into markOops for use by adjust_pointers. If "dest" should overflow, we | |
79 // finish by compacting into our own space. | |
80 | |
81 void PSMarkSweepDecorator::precompact() { | |
82 // Reset our own compact top. | |
83 set_compaction_top(space()->bottom()); | |
84 | |
85 /* We allow some amount of garbage towards the bottom of the space, so | |
86 * we don't start compacting before there is a significant gain to be made. | |
87 * Occasionally, we want to ensure a full compaction, which is determined | |
88 * by the MarkSweepAlwaysCompactCount parameter. This is a significant | |
89 * performance improvement! | |
90 */ | |
91 bool skip_dead = ((PSMarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0); | |
92 | |
438 | 93 size_t allowed_deadspace = 0; |
0 | 94 if (skip_dead) { |
438 | 95 const size_t ratio = allowed_dead_ratio(); |
96 allowed_deadspace = space()->capacity_in_words() * ratio / 100; | |
0 | 97 } |
98 | |
99 // Fetch the current destination decorator | |
100 PSMarkSweepDecorator* dest = destination_decorator(); | |
101 ObjectStartArray* start_array = dest->start_array(); | |
102 | |
103 HeapWord* compact_top = dest->compaction_top(); | |
104 HeapWord* compact_end = dest->space()->end(); | |
105 | |
106 HeapWord* q = space()->bottom(); | |
107 HeapWord* t = space()->top(); | |
108 | |
109 HeapWord* end_of_live= q; /* One byte beyond the last byte of the last | |
110 live object. */ | |
111 HeapWord* first_dead = space()->end(); /* The first dead object. */ | |
112 LiveRange* liveRange = NULL; /* The current live range, recorded in the | |
113 first header of preceding free area. */ | |
114 _first_dead = first_dead; | |
115 | |
116 const intx interval = PrefetchScanIntervalInBytes; | |
117 | |
118 while (q < t) { | |
119 assert(oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() || | |
120 oop(q)->mark()->has_bias_pattern(), | |
121 "these are the only valid states during a mark sweep"); | |
122 if (oop(q)->is_gc_marked()) { | |
123 /* prefetch beyond q */ | |
124 Prefetch::write(q, interval); | |
125 size_t size = oop(q)->size(); | |
126 | |
127 size_t compaction_max_size = pointer_delta(compact_end, compact_top); | |
128 | |
129 // This should only happen if a space in the young gen overflows the | |
130 // old gen. If that should happen, we null out the start_array, because | |
131 // the young spaces are not covered by one. | |
132 while(size > compaction_max_size) { | |
133 // First record the last compact_top | |
134 dest->set_compaction_top(compact_top); | |
135 | |
136 // Advance to the next compaction decorator | |
137 advance_destination_decorator(); | |
138 dest = destination_decorator(); | |
139 | |
140 // Update compaction info | |
141 start_array = dest->start_array(); | |
142 compact_top = dest->compaction_top(); | |
143 compact_end = dest->space()->end(); | |
144 assert(compact_top == dest->space()->bottom(), "Advanced to space already in use"); | |
145 assert(compact_end > compact_top, "Must always be space remaining"); | |
146 compaction_max_size = | |
147 pointer_delta(compact_end, compact_top); | |
148 } | |
149 | |
150 // store the forwarding pointer into the mark word | |
151 if (q != compact_top) { | |
152 oop(q)->forward_to(oop(compact_top)); | |
153 assert(oop(q)->is_gc_marked(), "encoding the pointer should preserve the mark"); | |
154 } else { | |
374
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
155 // if the object isn't moving we can just set the mark to the default |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
156 // mark and handle it specially later on. |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
157 oop(q)->init_mark(); |
0 | 158 assert(oop(q)->forwardee() == NULL, "should be forwarded to NULL"); |
159 } | |
160 | |
161 // Update object start array | |
374
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
162 if (start_array) { |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
163 start_array->allocate_block(compact_top); |
0 | 164 } |
165 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
166 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::register_live_oop(oop(q), size)); |
0 | 167 compact_top += size; |
168 assert(compact_top <= dest->space()->end(), | |
169 "Exceeding space in destination"); | |
170 | |
171 q += size; | |
172 end_of_live = q; | |
173 } else { | |
174 /* run over all the contiguous dead objects */ | |
175 HeapWord* end = q; | |
176 do { | |
177 /* prefetch beyond end */ | |
178 Prefetch::write(end, interval); | |
179 end += oop(end)->size(); | |
180 } while (end < t && (!oop(end)->is_gc_marked())); | |
181 | |
182 /* see if we might want to pretend this object is alive so that | |
183 * we don't have to compact quite as often. | |
184 */ | |
185 if (allowed_deadspace > 0 && q == compact_top) { | |
186 size_t sz = pointer_delta(end, q); | |
187 if (insert_deadspace(allowed_deadspace, q, sz)) { | |
188 size_t compaction_max_size = pointer_delta(compact_end, compact_top); | |
189 | |
190 // This should only happen if a space in the young gen overflows the | |
191 // old gen. If that should happen, we null out the start_array, because | |
192 // the young spaces are not covered by one. | |
193 while (sz > compaction_max_size) { | |
194 // First record the last compact_top | |
195 dest->set_compaction_top(compact_top); | |
196 | |
197 // Advance to the next compaction decorator | |
198 advance_destination_decorator(); | |
199 dest = destination_decorator(); | |
200 | |
201 // Update compaction info | |
202 start_array = dest->start_array(); | |
203 compact_top = dest->compaction_top(); | |
204 compact_end = dest->space()->end(); | |
205 assert(compact_top == dest->space()->bottom(), "Advanced to space already in use"); | |
206 assert(compact_end > compact_top, "Must always be space remaining"); | |
207 compaction_max_size = | |
208 pointer_delta(compact_end, compact_top); | |
209 } | |
210 | |
211 // store the forwarding pointer into the mark word | |
212 if (q != compact_top) { | |
213 oop(q)->forward_to(oop(compact_top)); | |
214 assert(oop(q)->is_gc_marked(), "encoding the pointer should preserve the mark"); | |
215 } else { | |
216 // if the object isn't moving we can just set the mark to the default | |
374
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
217 // mark and handle it specially later on. |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
218 oop(q)->init_mark(); |
0 | 219 assert(oop(q)->forwardee() == NULL, "should be forwarded to NULL"); |
220 } | |
221 | |
374
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
222 // Update object start array |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
223 if (start_array) { |
a4b729f5b611
6716466: par compact - remove VerifyParallelOldWithMarkSweep code
jcoomes
parents:
269
diff
changeset
|
224 start_array->allocate_block(compact_top); |
0 | 225 } |
226 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
227 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::register_live_oop(oop(q), sz)); |
0 | 228 compact_top += sz; |
229 assert(compact_top <= dest->space()->end(), | |
230 "Exceeding space in destination"); | |
231 | |
232 q = end; | |
233 end_of_live = end; | |
234 continue; | |
235 } | |
236 } | |
237 | |
238 /* for the previous LiveRange, record the end of the live objects. */ | |
239 if (liveRange) { | |
240 liveRange->set_end(q); | |
241 } | |
242 | |
243 /* record the current LiveRange object. | |
244 * liveRange->start() is overlaid on the mark word. | |
245 */ | |
246 liveRange = (LiveRange*)q; | |
247 liveRange->set_start(end); | |
248 liveRange->set_end(end); | |
249 | |
250 /* see if this is the first dead region. */ | |
251 if (q < first_dead) { | |
252 first_dead = q; | |
253 } | |
254 | |
255 /* move on to the next object */ | |
256 q = end; | |
257 } | |
258 } | |
259 | |
260 assert(q == t, "just checking"); | |
261 if (liveRange != NULL) { | |
262 liveRange->set_end(q); | |
263 } | |
264 _end_of_live = end_of_live; | |
265 if (end_of_live < first_dead) { | |
266 first_dead = end_of_live; | |
267 } | |
268 _first_dead = first_dead; | |
269 | |
270 // Update compaction top | |
271 dest->set_compaction_top(compact_top); | |
272 } | |
273 | |
438 | 274 bool PSMarkSweepDecorator::insert_deadspace(size_t& allowed_deadspace_words, |
275 HeapWord* q, size_t deadlength) { | |
276 if (allowed_deadspace_words >= deadlength) { | |
277 allowed_deadspace_words -= deadlength; | |
481
7d7a7c599c17
6578152: fill_region_with_object has usability and safety issues
jcoomes
parents:
438
diff
changeset
|
278 CollectedHeap::fill_with_object(q, deadlength); |
7d7a7c599c17
6578152: fill_region_with_object has usability and safety issues
jcoomes
parents:
438
diff
changeset
|
279 oop(q)->set_mark(oop(q)->mark()->set_marked()); |
7d7a7c599c17
6578152: fill_region_with_object has usability and safety issues
jcoomes
parents:
438
diff
changeset
|
280 assert((int) deadlength == oop(q)->size(), "bad filler object size"); |
0 | 281 // Recall that we required "q == compaction_top". |
282 return true; | |
283 } else { | |
284 allowed_deadspace_words = 0; | |
285 return false; | |
286 } | |
287 } | |
288 | |
289 void PSMarkSweepDecorator::adjust_pointers() { | |
290 // adjust all the interior pointers to point at the new locations of objects | |
291 // Used by MarkSweep::mark_sweep_phase3() | |
292 | |
293 HeapWord* q = space()->bottom(); | |
294 HeapWord* t = _end_of_live; // Established by "prepare_for_compaction". | |
295 | |
296 assert(_first_dead <= _end_of_live, "Stands to reason, no?"); | |
297 | |
298 if (q < t && _first_dead > q && | |
299 !oop(q)->is_gc_marked()) { | |
300 // we have a chunk of the space which hasn't moved and we've | |
301 // reinitialized the mark word during the previous pass, so we can't | |
302 // use is_gc_marked for the traversal. | |
303 HeapWord* end = _first_dead; | |
304 | |
305 while (q < end) { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
306 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::track_interior_pointers(oop(q))); |
0 | 307 // point all the oops to the new location |
308 size_t size = oop(q)->adjust_pointers(); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
309 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::check_interior_pointers()); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
310 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::validate_live_oop(oop(q), size)); |
0 | 311 q += size; |
312 } | |
313 | |
314 if (_first_dead == t) { | |
315 q = t; | |
316 } else { | |
317 // $$$ This is funky. Using this to read the previously written | |
318 // LiveRange. See also use below. | |
319 q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); | |
320 } | |
321 } | |
322 const intx interval = PrefetchScanIntervalInBytes; | |
323 | |
324 debug_only(HeapWord* prev_q = NULL); | |
325 while (q < t) { | |
326 // prefetch beyond q | |
327 Prefetch::write(q, interval); | |
328 if (oop(q)->is_gc_marked()) { | |
329 // q is alive | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
330 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::track_interior_pointers(oop(q))); |
0 | 331 // point all the oops to the new location |
332 size_t size = oop(q)->adjust_pointers(); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
333 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::check_interior_pointers()); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
334 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::validate_live_oop(oop(q), size)); |
0 | 335 debug_only(prev_q = q); |
336 q += size; | |
337 } else { | |
338 // q is not a live object, so its mark should point at the next | |
339 // live object | |
340 debug_only(prev_q = q); | |
341 q = (HeapWord*) oop(q)->mark()->decode_pointer(); | |
342 assert(q > prev_q, "we should be moving forward through memory"); | |
343 } | |
344 } | |
345 | |
346 assert(q == t, "just checking"); | |
347 } | |
348 | |
349 void PSMarkSweepDecorator::compact(bool mangle_free_space ) { | |
350 // Copy all live objects to their new location | |
351 // Used by MarkSweep::mark_sweep_phase4() | |
352 | |
353 HeapWord* q = space()->bottom(); | |
354 HeapWord* const t = _end_of_live; | |
355 debug_only(HeapWord* prev_q = NULL); | |
356 | |
357 if (q < t && _first_dead > q && | |
358 !oop(q)->is_gc_marked()) { | |
359 #ifdef ASSERT | |
360 // we have a chunk of the space which hasn't moved and we've reinitialized the | |
361 // mark word during the previous pass, so we can't use is_gc_marked for the | |
362 // traversal. | |
363 HeapWord* const end = _first_dead; | |
364 | |
365 while (q < end) { | |
366 size_t size = oop(q)->size(); | |
367 assert(!oop(q)->is_gc_marked(), "should be unmarked (special dense prefix handling)"); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
368 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::live_oop_moved_to(q, size, q)); |
0 | 369 debug_only(prev_q = q); |
370 q += size; | |
371 } | |
372 #endif | |
373 | |
374 if (_first_dead == t) { | |
375 q = t; | |
376 } else { | |
377 // $$$ Funky | |
378 q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); | |
379 } | |
380 } | |
381 | |
382 const intx scan_interval = PrefetchScanIntervalInBytes; | |
383 const intx copy_interval = PrefetchCopyIntervalInBytes; | |
384 | |
385 while (q < t) { | |
386 if (!oop(q)->is_gc_marked()) { | |
387 // mark is pointer to next marked oop | |
388 debug_only(prev_q = q); | |
389 q = (HeapWord*) oop(q)->mark()->decode_pointer(); | |
390 assert(q > prev_q, "we should be moving forward through memory"); | |
391 } else { | |
392 // prefetch beyond q | |
393 Prefetch::read(q, scan_interval); | |
394 | |
395 // size and destination | |
396 size_t size = oop(q)->size(); | |
397 HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); | |
398 | |
399 // prefetch beyond compaction_top | |
400 Prefetch::write(compaction_top, copy_interval); | |
401 | |
402 // copy object and reinit its mark | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
403 VALIDATE_MARK_SWEEP_ONLY(MarkSweep::live_oop_moved_to(q, size, compaction_top)); |
0 | 404 assert(q != compaction_top, "everything in this pass should be moving"); |
405 Copy::aligned_conjoint_words(q, compaction_top, size); | |
406 oop(compaction_top)->init_mark(); | |
407 assert(oop(compaction_top)->klass() != NULL, "should have a class"); | |
408 | |
409 debug_only(prev_q = q); | |
410 q += size; | |
411 } | |
412 } | |
413 | |
414 assert(compaction_top() >= space()->bottom() && compaction_top() <= space()->end(), | |
415 "should point inside space"); | |
416 space()->set_top(compaction_top()); | |
417 | |
263
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
113
diff
changeset
|
418 if (mangle_free_space) { |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
113
diff
changeset
|
419 space()->mangle_unused_area(); |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
113
diff
changeset
|
420 } |
0 | 421 } |