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) {