Mercurial > hg > truffle
comparison src/share/vm/memory/referenceProcessor.cpp @ 452:00b023ae2d78
6722113: CMS: Incorrect overflow handling during precleaning of Reference lists
Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery.
Reviewed-by: apetrusenko, jcoomes
author | ysr |
---|---|
date | Thu, 20 Nov 2008 12:27:41 -0800 |
parents | 1ee8caae33af |
children | c96030fff130 |
comparison
equal
deleted
inserted
replaced
443:b5e603f2e024 | 452:00b023ae2d78 |
---|---|
45 _oop_head = o; | 45 _oop_head = o; |
46 } | 46 } |
47 } | 47 } |
48 bool empty() const { return head() == ReferenceProcessor::sentinel_ref(); } | 48 bool empty() const { return head() == ReferenceProcessor::sentinel_ref(); } |
49 size_t length() { return _len; } | 49 size_t length() { return _len; } |
50 void set_length(size_t len) { _len = len; } | 50 void set_length(size_t len) { _len = len; } |
51 void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error"); } | |
52 void dec_length(size_t dec) { _len -= dec; } | |
51 private: | 53 private: |
52 // Set value depending on UseCompressedOops. This could be a template class | 54 // Set value depending on UseCompressedOops. This could be a template class |
53 // but then we have to fix all the instantiations and declarations that use this class. | 55 // but then we have to fix all the instantiations and declarations that use this class. |
54 oop _oop_head; | 56 oop _oop_head; |
55 narrowOop _compressed_head; | 57 narrowOop _compressed_head; |
434 | 436 |
435 // Loads data for the current reference. | 437 // Loads data for the current reference. |
436 // The "allow_null_referent" argument tells us to allow for the possibility | 438 // The "allow_null_referent" argument tells us to allow for the possibility |
437 // of a NULL referent in the discovered Reference object. This typically | 439 // of a NULL referent in the discovered Reference object. This typically |
438 // happens in the case of concurrent collectors that may have done the | 440 // happens in the case of concurrent collectors that may have done the |
439 // discovery concurrently or interleaved with mutator execution. | 441 // discovery concurrently, or interleaved, with mutator execution. |
440 inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent)); | 442 inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent)); |
441 | 443 |
442 // Move to the next discovered reference. | 444 // Move to the next discovered reference. |
443 inline void next(); | 445 inline void next(); |
444 | 446 |
445 // Remove the current reference from the list and move to the next. | 447 // Remove the current reference from the list |
446 inline void remove(); | 448 inline void remove(); |
447 | 449 |
448 // Make the Reference object active again. | 450 // Make the Reference object active again. |
449 inline void make_active() { java_lang_ref_Reference::set_next(_ref, NULL); } | 451 inline void make_active() { java_lang_ref_Reference::set_next(_ref, NULL); } |
450 | 452 |
474 NOT_PRODUCT( | 476 NOT_PRODUCT( |
475 inline size_t processed() const { return _processed; } | 477 inline size_t processed() const { return _processed; } |
476 inline size_t removed() const { return _removed; } | 478 inline size_t removed() const { return _removed; } |
477 ) | 479 ) |
478 | 480 |
479 private: | |
480 inline void move_to_next(); | 481 inline void move_to_next(); |
481 | 482 |
482 private: | 483 private: |
483 DiscoveredList& _refs_list; | 484 DiscoveredList& _refs_list; |
484 HeapWord* _prev_next; | 485 HeapWord* _prev_next; |
551 } else { | 552 } else { |
552 // Remove Reference object from list. | 553 // Remove Reference object from list. |
553 oopDesc::store_heap_oop((oop*)_prev_next, _next); | 554 oopDesc::store_heap_oop((oop*)_prev_next, _next); |
554 } | 555 } |
555 NOT_PRODUCT(_removed++); | 556 NOT_PRODUCT(_removed++); |
556 move_to_next(); | 557 _refs_list.dec_length(1); |
557 } | 558 } |
558 | 559 |
559 inline void DiscoveredListIterator::move_to_next() { | 560 inline void DiscoveredListIterator::move_to_next() { |
560 _ref = _next; | 561 _ref = _next; |
561 assert(_ref != _first_seen, "cyclic ref_list found"); | 562 assert(_ref != _first_seen, "cyclic ref_list found"); |
589 if (referent_is_dead && !policy->should_clear_reference(iter.obj())) { | 590 if (referent_is_dead && !policy->should_clear_reference(iter.obj())) { |
590 if (TraceReferenceGC) { | 591 if (TraceReferenceGC) { |
591 gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", | 592 gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy", |
592 iter.obj(), iter.obj()->blueprint()->internal_name()); | 593 iter.obj(), iter.obj()->blueprint()->internal_name()); |
593 } | 594 } |
595 // Remove Reference object from list | |
596 iter.remove(); | |
594 // Make the Reference object active again | 597 // Make the Reference object active again |
595 iter.make_active(); | 598 iter.make_active(); |
596 // keep the referent around | 599 // keep the referent around |
597 iter.make_referent_alive(); | 600 iter.make_referent_alive(); |
598 // Remove Reference object from list | 601 iter.move_to_next(); |
599 iter.remove(); | |
600 } else { | 602 } else { |
601 iter.next(); | 603 iter.next(); |
602 } | 604 } |
603 } | 605 } |
604 // Close the reachable set | 606 // Close the reachable set |
627 if (TraceReferenceGC) { | 629 if (TraceReferenceGC) { |
628 gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", | 630 gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)", |
629 iter.obj(), iter.obj()->blueprint()->internal_name()); | 631 iter.obj(), iter.obj()->blueprint()->internal_name()); |
630 } | 632 } |
631 // The referent is reachable after all. | 633 // The referent is reachable after all. |
634 // Remove Reference object from list. | |
635 iter.remove(); | |
632 // Update the referent pointer as necessary: Note that this | 636 // Update the referent pointer as necessary: Note that this |
633 // should not entail any recursive marking because the | 637 // should not entail any recursive marking because the |
634 // referent must already have been traversed. | 638 // referent must already have been traversed. |
635 iter.make_referent_alive(); | 639 iter.make_referent_alive(); |
636 // Remove Reference object from list | 640 iter.move_to_next(); |
637 iter.remove(); | |
638 } else { | 641 } else { |
639 iter.next(); | 642 iter.next(); |
640 } | 643 } |
641 } | 644 } |
642 NOT_PRODUCT( | 645 NOT_PRODUCT( |
668 if (UseCompressedOops) { | 671 if (UseCompressedOops) { |
669 keep_alive->do_oop((narrowOop*)next_addr); | 672 keep_alive->do_oop((narrowOop*)next_addr); |
670 } else { | 673 } else { |
671 keep_alive->do_oop((oop*)next_addr); | 674 keep_alive->do_oop((oop*)next_addr); |
672 } | 675 } |
676 iter.move_to_next(); | |
673 } else { | 677 } else { |
674 iter.next(); | 678 iter.next(); |
675 } | 679 } |
676 } | 680 } |
677 // Now close the newly reachable set | 681 // Now close the newly reachable set |
830 move_tail = new_head; | 834 move_tail = new_head; |
831 new_head = java_lang_ref_Reference::discovered(new_head); | 835 new_head = java_lang_ref_Reference::discovered(new_head); |
832 } | 836 } |
833 java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head()); | 837 java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head()); |
834 ref_lists[to_idx].set_head(move_head); | 838 ref_lists[to_idx].set_head(move_head); |
835 ref_lists[to_idx].set_length(ref_lists[to_idx].length() + refs_to_move); | 839 ref_lists[to_idx].inc_length(refs_to_move); |
836 ref_lists[from_idx].set_head(new_head); | 840 ref_lists[from_idx].set_head(new_head); |
837 ref_lists[from_idx].set_length(ref_lists[from_idx].length() - refs_to_move); | 841 ref_lists[from_idx].dec_length(refs_to_move); |
838 } else { | 842 } else { |
839 ++to_idx; | 843 ++to_idx; |
840 } | 844 } |
841 } | 845 } |
842 } | 846 } |
921 } | 925 } |
922 | 926 |
923 void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) { | 927 void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) { |
924 assert(!discovery_is_atomic(), "Else why call this method?"); | 928 assert(!discovery_is_atomic(), "Else why call this method?"); |
925 DiscoveredListIterator iter(refs_list, NULL, NULL); | 929 DiscoveredListIterator iter(refs_list, NULL, NULL); |
926 size_t length = refs_list.length(); | |
927 while (iter.has_next()) { | 930 while (iter.has_next()) { |
928 iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); | 931 iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); |
929 oop next = java_lang_ref_Reference::next(iter.obj()); | 932 oop next = java_lang_ref_Reference::next(iter.obj()); |
930 assert(next->is_oop_or_null(), "bad next field"); | 933 assert(next->is_oop_or_null(), "bad next field"); |
931 // If referent has been cleared or Reference is not active, | 934 // If referent has been cleared or Reference is not active, |
939 iter.obj(), next, iter.referent()); | 942 iter.obj(), next, iter.referent()); |
940 } | 943 } |
941 ) | 944 ) |
942 // Remove Reference object from list | 945 // Remove Reference object from list |
943 iter.remove(); | 946 iter.remove(); |
944 --length; | 947 iter.move_to_next(); |
945 } else { | 948 } else { |
946 iter.next(); | 949 iter.next(); |
947 } | 950 } |
948 } | 951 } |
949 refs_list.set_length(length); | |
950 NOT_PRODUCT( | 952 NOT_PRODUCT( |
951 if (PrintGCDetails && TraceReferenceGC) { | 953 if (PrintGCDetails && TraceReferenceGC) { |
952 gclog_or_tty->print( | 954 gclog_or_tty->print( |
953 " Removed %d Refs with NULL referents out of %d discovered Refs", | 955 " Removed %d Refs with NULL referents out of %d discovered Refs", |
954 iter.removed(), iter.processed()); | 956 iter.removed(), iter.processed()); |
1022 if (retest == NULL) { | 1024 if (retest == NULL) { |
1023 // This thread just won the right to enqueue the object. | 1025 // This thread just won the right to enqueue the object. |
1024 // We have separate lists for enqueueing so no synchronization | 1026 // We have separate lists for enqueueing so no synchronization |
1025 // is necessary. | 1027 // is necessary. |
1026 refs_list.set_head(obj); | 1028 refs_list.set_head(obj); |
1027 refs_list.set_length(refs_list.length() + 1); | 1029 refs_list.inc_length(1); |
1028 if (_discovered_list_needs_barrier) { | 1030 if (_discovered_list_needs_barrier) { |
1029 _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR"); | 1031 _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR"); |
1030 } | 1032 } |
1031 | 1033 |
1032 } else { | 1034 } else { |
1166 oop_store_raw(discovered_addr, current_head); | 1168 oop_store_raw(discovered_addr, current_head); |
1167 if (_discovered_list_needs_barrier) { | 1169 if (_discovered_list_needs_barrier) { |
1168 _bs->write_ref_field((oop*)discovered_addr, current_head); | 1170 _bs->write_ref_field((oop*)discovered_addr, current_head); |
1169 } | 1171 } |
1170 list->set_head(obj); | 1172 list->set_head(obj); |
1171 list->set_length(list->length() + 1); | 1173 list->inc_length(1); |
1172 } | 1174 } |
1173 | 1175 |
1174 // In the MT discovery case, it is currently possible to see | 1176 // In the MT discovery case, it is currently possible to see |
1175 // the following message multiple times if several threads | 1177 // the following message multiple times if several threads |
1176 // discover a reference about the same time. Only one will | 1178 // discover a reference about the same time. Only one will |
1207 // Soft references | 1209 // Soft references |
1208 { | 1210 { |
1209 TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, | 1211 TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, |
1210 false, gclog_or_tty); | 1212 false, gclog_or_tty); |
1211 for (int i = 0; i < _num_q; i++) { | 1213 for (int i = 0; i < _num_q; i++) { |
1214 if (yield->should_return()) { | |
1215 return; | |
1216 } | |
1212 preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive, | 1217 preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive, |
1213 keep_alive, complete_gc, yield); | 1218 keep_alive, complete_gc, yield); |
1214 } | 1219 } |
1215 } | |
1216 if (yield->should_return()) { | |
1217 return; | |
1218 } | 1220 } |
1219 | 1221 |
1220 // Weak references | 1222 // Weak references |
1221 { | 1223 { |
1222 TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, | 1224 TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, |
1223 false, gclog_or_tty); | 1225 false, gclog_or_tty); |
1224 for (int i = 0; i < _num_q; i++) { | 1226 for (int i = 0; i < _num_q; i++) { |
1227 if (yield->should_return()) { | |
1228 return; | |
1229 } | |
1225 preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive, | 1230 preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive, |
1226 keep_alive, complete_gc, yield); | 1231 keep_alive, complete_gc, yield); |
1227 } | 1232 } |
1228 } | |
1229 if (yield->should_return()) { | |
1230 return; | |
1231 } | 1233 } |
1232 | 1234 |
1233 // Final references | 1235 // Final references |
1234 { | 1236 { |
1235 TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, | 1237 TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, |
1236 false, gclog_or_tty); | 1238 false, gclog_or_tty); |
1237 for (int i = 0; i < _num_q; i++) { | 1239 for (int i = 0; i < _num_q; i++) { |
1240 if (yield->should_return()) { | |
1241 return; | |
1242 } | |
1238 preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive, | 1243 preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive, |
1239 keep_alive, complete_gc, yield); | 1244 keep_alive, complete_gc, yield); |
1240 } | 1245 } |
1241 } | |
1242 if (yield->should_return()) { | |
1243 return; | |
1244 } | 1246 } |
1245 | 1247 |
1246 // Phantom references | 1248 // Phantom references |
1247 { | 1249 { |
1248 TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, | 1250 TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, |
1249 false, gclog_or_tty); | 1251 false, gclog_or_tty); |
1250 for (int i = 0; i < _num_q; i++) { | 1252 for (int i = 0; i < _num_q; i++) { |
1253 if (yield->should_return()) { | |
1254 return; | |
1255 } | |
1251 preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, | 1256 preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, |
1252 keep_alive, complete_gc, yield); | 1257 keep_alive, complete_gc, yield); |
1253 } | 1258 } |
1254 } | 1259 } |
1255 } | 1260 } |
1256 | 1261 |
1257 // Walk the given discovered ref list, and remove all reference objects | 1262 // Walk the given discovered ref list, and remove all reference objects |
1258 // whose referents are still alive, whose referents are NULL or which | 1263 // whose referents are still alive, whose referents are NULL or which |
1259 // are not active (have a non-NULL next field). NOTE: For this to work | 1264 // are not active (have a non-NULL next field). NOTE: When we are |
1260 // correctly, refs discovery can not be happening concurrently with this | 1265 // thus precleaning the ref lists (which happens single-threaded today), |
1261 // step. | 1266 // we do not disable refs discovery to honour the correct semantics of |
1267 // java.lang.Reference. As a result, we need to be careful below | |
1268 // that ref removal steps interleave safely with ref discovery steps | |
1269 // (in this thread). | |
1262 void | 1270 void |
1263 ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, | 1271 ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, |
1264 BoolObjectClosure* is_alive, | 1272 BoolObjectClosure* is_alive, |
1265 OopClosure* keep_alive, | 1273 OopClosure* keep_alive, |
1266 VoidClosure* complete_gc, | 1274 VoidClosure* complete_gc, |
1267 YieldClosure* yield) { | 1275 YieldClosure* yield) { |
1268 DiscoveredListIterator iter(refs_list, keep_alive, is_alive); | 1276 DiscoveredListIterator iter(refs_list, keep_alive, is_alive); |
1269 size_t length = refs_list.length(); | |
1270 while (iter.has_next()) { | 1277 while (iter.has_next()) { |
1271 iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); | 1278 iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); |
1272 oop obj = iter.obj(); | 1279 oop obj = iter.obj(); |
1273 oop next = java_lang_ref_Reference::next(obj); | 1280 oop next = java_lang_ref_Reference::next(obj); |
1274 if (iter.referent() == NULL || iter.is_referent_alive() || | 1281 if (iter.referent() == NULL || iter.is_referent_alive() || |
1279 gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)", | 1286 gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)", |
1280 iter.obj(), iter.obj()->blueprint()->internal_name()); | 1287 iter.obj(), iter.obj()->blueprint()->internal_name()); |
1281 } | 1288 } |
1282 // Remove Reference object from list | 1289 // Remove Reference object from list |
1283 iter.remove(); | 1290 iter.remove(); |
1284 --length; | |
1285 // Keep alive its cohort. | 1291 // Keep alive its cohort. |
1286 iter.make_referent_alive(); | 1292 iter.make_referent_alive(); |
1287 if (UseCompressedOops) { | 1293 if (UseCompressedOops) { |
1288 narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj); | 1294 narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj); |
1289 keep_alive->do_oop(next_addr); | 1295 keep_alive->do_oop(next_addr); |
1290 } else { | 1296 } else { |
1291 oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj); | 1297 oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj); |
1292 keep_alive->do_oop(next_addr); | 1298 keep_alive->do_oop(next_addr); |
1293 } | 1299 } |
1300 iter.move_to_next(); | |
1294 } else { | 1301 } else { |
1295 iter.next(); | 1302 iter.next(); |
1296 } | 1303 } |
1297 } | 1304 } |
1298 refs_list.set_length(length); | |
1299 | |
1300 // Close the reachable set | 1305 // Close the reachable set |
1301 complete_gc->do_void(); | 1306 complete_gc->do_void(); |
1302 | 1307 |
1303 NOT_PRODUCT( | 1308 NOT_PRODUCT( |
1304 if (PrintGCDetails && PrintReferenceGC) { | 1309 if (PrintGCDetails && PrintReferenceGC) { |