src/share/vm/memory/referenceProcessor.cpp

Print this page




  31   DiscoveredList() : _len(0), _compressed_head(0), _oop_head(NULL) { }
  32   oop head() const     {
  33      return UseCompressedOops ?  oopDesc::decode_heap_oop_not_null(_compressed_head) :
  34                                 _oop_head;
  35   }
  36   HeapWord* adr_head() {
  37     return UseCompressedOops ? (HeapWord*)&_compressed_head :
  38                                (HeapWord*)&_oop_head;
  39   }
  40   void   set_head(oop o) {
  41     if (UseCompressedOops) {
  42       // Must compress the head ptr.
  43       _compressed_head = oopDesc::encode_heap_oop_not_null(o);
  44     } else {
  45       _oop_head = o;
  46     }
  47   }
  48   bool   empty() const          { return head() == ReferenceProcessor::sentinel_ref(); }
  49   size_t length()               { return _len; }
  50   void   set_length(size_t len) { _len = len; }


  51 private:
  52   // 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.
  54   oop       _oop_head;
  55   narrowOop _compressed_head;
  56   size_t _len;
  57 };
  58 
  59 oop  ReferenceProcessor::_sentinelRef = NULL;
  60 
  61 const int subclasses_of_ref = REF_PHANTOM - REF_OTHER;
  62 
  63 void referenceProcessor_init() {
  64   ReferenceProcessor::init_statics();
  65 }
  66 
  67 void ReferenceProcessor::init_statics() {
  68   assert(_sentinelRef == NULL, "should be initialized precisely once");
  69   EXCEPTION_MARK;
  70   _sentinelRef = instanceKlass::cast(


 419   inline DiscoveredListIterator(DiscoveredList&    refs_list,
 420                                 OopClosure*        keep_alive,
 421                                 BoolObjectClosure* is_alive);
 422 
 423   // End Of List.
 424   inline bool has_next() const { return _next != ReferenceProcessor::sentinel_ref(); }
 425 
 426   // Get oop to the Reference object.
 427   inline oop obj() const { return _ref; }
 428 
 429   // Get oop to the referent object.
 430   inline oop referent() const { return _referent; }
 431 
 432   // Returns true if referent is alive.
 433   inline bool is_referent_alive() const;
 434 
 435   // Loads data for the current reference.
 436   // The "allow_null_referent" argument tells us to allow for the possibility
 437   // of a NULL referent in the discovered Reference object. This typically
 438   // happens in the case of concurrent collectors that may have done the
 439   // discovery concurrently or interleaved with mutator execution.
 440   inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
 441 
 442   // Move to the next discovered reference.
 443   inline void next();
 444 
 445   // Remove the current reference from the list and move to the next.
 446   inline void remove();
 447 
 448   // Make the Reference object active again.
 449   inline void make_active() { java_lang_ref_Reference::set_next(_ref, NULL); }
 450 
 451   // Make the referent alive.
 452   inline void make_referent_alive() {
 453     if (UseCompressedOops) {
 454       _keep_alive->do_oop((narrowOop*)_referent_addr);
 455     } else {
 456       _keep_alive->do_oop((oop*)_referent_addr);
 457     }
 458   }
 459 
 460   // Update the discovered field.
 461   inline void update_discovered() {
 462     // First _prev_next ref actually points into DiscoveredList (gross).
 463     if (UseCompressedOops) {
 464       _keep_alive->do_oop((narrowOop*)_prev_next);
 465     } else {
 466       _keep_alive->do_oop((oop*)_prev_next);
 467     }
 468   }
 469 
 470   // NULL out referent pointer.
 471   inline void clear_referent() { oop_store_raw(_referent_addr, NULL); }
 472 
 473   // Statistics
 474   NOT_PRODUCT(
 475   inline size_t processed() const { return _processed; }
 476   inline size_t removed() const   { return _removed; }
 477   )
 478 
 479 private:
 480   inline void move_to_next();
 481 
 482 private:
 483   DiscoveredList&    _refs_list;
 484   HeapWord*          _prev_next;
 485   oop                _ref;
 486   HeapWord*          _discovered_addr;
 487   oop                _next;
 488   HeapWord*          _referent_addr;
 489   oop                _referent;
 490   OopClosure*        _keep_alive;
 491   BoolObjectClosure* _is_alive;
 492   DEBUG_ONLY(
 493   oop                _first_seen; // cyclic linked list check
 494   )
 495   NOT_PRODUCT(
 496   size_t             _processed;
 497   size_t             _removed;
 498   )
 499 };


 536          "bad referent");
 537 }
 538 
 539 inline void DiscoveredListIterator::next() {
 540   _prev_next = _discovered_addr;
 541   move_to_next();
 542 }
 543 
 544 inline void DiscoveredListIterator::remove() {
 545   assert(_ref->is_oop(), "Dropping a bad reference");
 546   oop_store_raw(_discovered_addr, NULL);
 547   // First _prev_next ref actually points into DiscoveredList (gross).
 548   if (UseCompressedOops) {
 549     // Remove Reference object from list.
 550     oopDesc::encode_store_heap_oop_not_null((narrowOop*)_prev_next, _next);
 551   } else {
 552     // Remove Reference object from list.
 553     oopDesc::store_heap_oop((oop*)_prev_next, _next);
 554   }
 555   NOT_PRODUCT(_removed++);
 556   move_to_next();
 557 }
 558 
 559 inline void DiscoveredListIterator::move_to_next() {
 560   _ref = _next;
 561   assert(_ref != _first_seen, "cyclic ref_list found");
 562   NOT_PRODUCT(_processed++);
 563 }
 564 
 565 // NOTE: process_phase*() are largely similar, and at a high level
 566 // merely iterate over the extant list applying a predicate to
 567 // each of its elements and possibly removing that element from the
 568 // list and applying some further closures to that element.
 569 // We should consider the possibility of replacing these
 570 // process_phase*() methods by abstracting them into
 571 // a single general iterator invocation that receives appropriate
 572 // closures that accomplish this work.
 573 
 574 // (SoftReferences only) Traverse the list and remove any SoftReferences whose
 575 // referents are not alive, but that should be kept alive for policy reasons.
 576 // Keep alive the transitive closure of all such referents.
 577 void
 578 ReferenceProcessor::process_phase1(DiscoveredList&    refs_list,
 579                                    ReferencePolicy*   policy,
 580                                    BoolObjectClosure* is_alive,
 581                                    OopClosure*        keep_alive,
 582                                    VoidClosure*       complete_gc) {
 583   assert(policy != NULL, "Must have a non-NULL policy");
 584   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 585   // Decide which softly reachable refs should be kept alive.
 586   while (iter.has_next()) {
 587     iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */));
 588     bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive();
 589     if (referent_is_dead && !policy->should_clear_reference(iter.obj())) {
 590       if (TraceReferenceGC) {
 591         gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s"  ") by policy",
 592                                iter.obj(), iter.obj()->blueprint()->internal_name());
 593       }


 594       // Make the Reference object active again
 595       iter.make_active();
 596       // keep the referent around
 597       iter.make_referent_alive();
 598       // Remove Reference object from list
 599       iter.remove();
 600     } else {
 601       iter.next();
 602     }
 603   }
 604   // Close the reachable set
 605   complete_gc->do_void();
 606   NOT_PRODUCT(
 607     if (PrintGCDetails && TraceReferenceGC) {
 608       gclog_or_tty->print(" Dropped %d dead Refs out of %d "
 609         "discovered Refs by policy ", iter.removed(), iter.processed());
 610     }
 611   )
 612 }
 613 
 614 // Traverse the list and remove any Refs that are not active, or
 615 // whose referents are either alive or NULL.
 616 void
 617 ReferenceProcessor::pp2_work(DiscoveredList&    refs_list,
 618                              BoolObjectClosure* is_alive,
 619                              OopClosure*        keep_alive) {
 620   assert(discovery_is_atomic(), "Error");
 621   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 622   while (iter.has_next()) {
 623     iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));
 624     DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());)
 625     assert(next == NULL, "Should not discover inactive Reference");
 626     if (iter.is_referent_alive()) {
 627       if (TraceReferenceGC) {
 628         gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)",
 629                                iter.obj(), iter.obj()->blueprint()->internal_name());
 630       }
 631       // The referent is reachable after all.


 632       // Update the referent pointer as necessary: Note that this
 633       // should not entail any recursive marking because the
 634       // referent must already have been traversed.
 635       iter.make_referent_alive();
 636       // Remove Reference object from list
 637       iter.remove();
 638     } else {
 639       iter.next();
 640     }
 641   }
 642   NOT_PRODUCT(
 643     if (PrintGCDetails && TraceReferenceGC) {
 644       gclog_or_tty->print(" Dropped %d active Refs out of %d "
 645         "Refs in discovered list ", iter.removed(), iter.processed());
 646     }
 647   )
 648 }
 649 
 650 void
 651 ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList&    refs_list,
 652                                                   BoolObjectClosure* is_alive,
 653                                                   OopClosure*        keep_alive,
 654                                                   VoidClosure*       complete_gc) {
 655   assert(!discovery_is_atomic(), "Error");
 656   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 657   while (iter.has_next()) {
 658     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
 659     HeapWord* next_addr = java_lang_ref_Reference::next_addr(iter.obj());
 660     oop next = java_lang_ref_Reference::next(iter.obj());
 661     if ((iter.referent() == NULL || iter.is_referent_alive() ||
 662          next != NULL)) {
 663       assert(next->is_oop_or_null(), "bad next field");
 664       // Remove Reference object from list
 665       iter.remove();
 666       // Trace the cohorts
 667       iter.make_referent_alive();
 668       if (UseCompressedOops) {
 669         keep_alive->do_oop((narrowOop*)next_addr);
 670       } else {
 671         keep_alive->do_oop((oop*)next_addr);
 672       }

 673     } else {
 674       iter.next();
 675     }
 676   }
 677   // Now close the newly reachable set
 678   complete_gc->do_void();
 679   NOT_PRODUCT(
 680     if (PrintGCDetails && TraceReferenceGC) {
 681       gclog_or_tty->print(" Dropped %d active Refs out of %d "
 682         "Refs in discovered list ", iter.removed(), iter.processed());
 683     }
 684   )
 685 }
 686 
 687 // Traverse the list and process the referents, by either
 688 // clearing them or keeping them (and their reachable
 689 // closure) alive.
 690 void
 691 ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,
 692                                    bool               clear_referent,


 815   size_t avg_refs = total_refs / _num_q + 1;
 816   int to_idx = 0;
 817   for (int from_idx = 0; from_idx < _num_q; from_idx++) {
 818     while (ref_lists[from_idx].length() > avg_refs) {
 819       assert(to_idx < _num_q, "Sanity Check!");
 820       if (ref_lists[to_idx].length() < avg_refs) {
 821         // move superfluous refs
 822         size_t refs_to_move =
 823           MIN2(ref_lists[from_idx].length() - avg_refs,
 824                avg_refs - ref_lists[to_idx].length());
 825         oop move_head = ref_lists[from_idx].head();
 826         oop move_tail = move_head;
 827         oop new_head  = move_head;
 828         // find an element to split the list on
 829         for (size_t j = 0; j < refs_to_move; ++j) {
 830           move_tail = new_head;
 831           new_head = java_lang_ref_Reference::discovered(new_head);
 832         }
 833         java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head());
 834         ref_lists[to_idx].set_head(move_head);
 835         ref_lists[to_idx].set_length(ref_lists[to_idx].length() + refs_to_move);
 836         ref_lists[from_idx].set_head(new_head);
 837         ref_lists[from_idx].set_length(ref_lists[from_idx].length() - refs_to_move);
 838       } else {
 839         ++to_idx;
 840       }
 841     }
 842   }
 843 }
 844 
 845 void
 846 ReferenceProcessor::process_discovered_reflist(
 847   DiscoveredList               refs_lists[],
 848   ReferencePolicy*             policy,
 849   bool                         clear_referent,
 850   BoolObjectClosure*           is_alive,
 851   OopClosure*                  keep_alive,
 852   VoidClosure*                 complete_gc,
 853   AbstractRefProcTaskExecutor* task_executor)
 854 {
 855   bool mt = task_executor != NULL && _processing_is_mt;
 856   if (mt && ParallelRefProcBalancingEnabled) {
 857     balance_queues(refs_lists);


 906                      is_alive, keep_alive, complete_gc);
 907     }
 908   }
 909 }
 910 
 911 void ReferenceProcessor::clean_up_discovered_references() {
 912   // loop over the lists
 913   for (int i = 0; i < _num_q * subclasses_of_ref; i++) {
 914     if (TraceReferenceGC && PrintGCDetails && ((i % _num_q) == 0)) {
 915       gclog_or_tty->print_cr(
 916         "\nScrubbing %s discovered list of Null referents",
 917         list_name(i));
 918     }
 919     clean_up_discovered_reflist(_discoveredSoftRefs[i]);
 920   }
 921 }
 922 
 923 void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
 924   assert(!discovery_is_atomic(), "Else why call this method?");
 925   DiscoveredListIterator iter(refs_list, NULL, NULL);
 926   size_t length = refs_list.length();
 927   while (iter.has_next()) {
 928     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
 929     oop next = java_lang_ref_Reference::next(iter.obj());
 930     assert(next->is_oop_or_null(), "bad next field");
 931     // If referent has been cleared or Reference is not active,
 932     // drop it.
 933     if (iter.referent() == NULL || next != NULL) {
 934       debug_only(
 935         if (PrintGCDetails && TraceReferenceGC) {
 936           gclog_or_tty->print_cr("clean_up_discovered_list: Dropping Reference: "
 937             INTPTR_FORMAT " with next field: " INTPTR_FORMAT
 938             " and referent: " INTPTR_FORMAT,
 939             iter.obj(), next, iter.referent());
 940         }
 941       )
 942       // Remove Reference object from list
 943       iter.remove();
 944       --length;
 945     } else {
 946       iter.next();
 947     }
 948   }
 949   refs_list.set_length(length);
 950   NOT_PRODUCT(
 951     if (PrintGCDetails && TraceReferenceGC) {
 952       gclog_or_tty->print(
 953         " Removed %d Refs with NULL referents out of %d discovered Refs",
 954         iter.removed(), iter.processed());
 955     }
 956   )
 957 }
 958 
 959 inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
 960   int id = 0;
 961   // Determine the queue index to use for this object.
 962   if (_discovery_is_mt) {
 963     // During a multi-threaded discovery phase,
 964     // each thread saves to its "own" list.
 965     Thread* thr = Thread::current();
 966     assert(thr->is_GC_task_thread(),
 967            "Dubious cast from Thread* to WorkerThread*?");
 968     id = ((WorkerThread*)thr)->id();
 969   } else {


1007                                               HeapWord*       discovered_addr) {
1008   assert(_discovery_is_mt, "!_discovery_is_mt should have been handled by caller");
1009   // First we must make sure this object is only enqueued once. CAS in a non null
1010   // discovered_addr.
1011   oop current_head = refs_list.head();
1012 
1013   // Note: In the case of G1, this pre-barrier is strictly
1014   // not necessary because the only case we are interested in
1015   // here is when *discovered_addr is NULL, so this will expand to
1016   // nothing. As a result, I am just manually eliding this out for G1.
1017   if (_discovered_list_needs_barrier && !UseG1GC) {
1018     _bs->write_ref_field_pre((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
1019   }
1020   oop retest = oopDesc::atomic_compare_exchange_oop(current_head, discovered_addr,
1021                                                     NULL);
1022   if (retest == NULL) {
1023     // This thread just won the right to enqueue the object.
1024     // We have separate lists for enqueueing so no synchronization
1025     // is necessary.
1026     refs_list.set_head(obj);
1027     refs_list.set_length(refs_list.length() + 1);
1028     if (_discovered_list_needs_barrier) {
1029       _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
1030     }
1031 
1032   } else {
1033     // If retest was non NULL, another thread beat us to it:
1034     // The reference has already been discovered...
1035     if (TraceReferenceGC) {
1036       gclog_or_tty->print_cr("Already enqueued reference (" INTPTR_FORMAT ": %s)",
1037                              obj, obj->blueprint()->internal_name());
1038     }
1039   }
1040 }
1041 
1042 // We mention two of several possible choices here:
1043 // #0: if the reference object is not in the "originating generation"
1044 //     (or part of the heap being collected, indicated by our "span"
1045 //     we don't treat it specially (i.e. we scan it as we would
1046 //     a normal oop, treating its references as strong references).
1047 //     This means that references can't be enqueued unless their


1151 
1152   if (_discovery_is_mt) {
1153     add_to_discovered_list_mt(*list, obj, discovered_addr);
1154   } else {
1155     // If "_discovered_list_needs_barrier", we do write barriers when
1156     // updating the discovered reference list.  Otherwise, we do a raw store
1157     // here: the field will be visited later when processing the discovered
1158     // references.
1159     oop current_head = list->head();
1160     // As in the case further above, since we are over-writing a NULL
1161     // pre-value, we can safely elide the pre-barrier here for the case of G1.
1162     assert(discovered == NULL, "control point invariant");
1163     if (_discovered_list_needs_barrier && !UseG1GC) { // safe to elide for G1
1164       _bs->write_ref_field_pre((oop*)discovered_addr, current_head);
1165     }
1166     oop_store_raw(discovered_addr, current_head);
1167     if (_discovered_list_needs_barrier) {
1168       _bs->write_ref_field((oop*)discovered_addr, current_head);
1169     }
1170     list->set_head(obj);
1171     list->set_length(list->length() + 1);
1172   }
1173 
1174   // In the MT discovery case, it is currently possible to see
1175   // the following message multiple times if several threads
1176   // discover a reference about the same time. Only one will
1177   // however have actually added it to the disocvered queue.
1178   // One could let add_to_discovered_list_mt() return an
1179   // indication for success in queueing (by 1 thread) or
1180   // failure (by all other threads), but I decided the extra
1181   // code was not worth the effort for something that is
1182   // only used for debugging support.
1183   if (TraceReferenceGC) {
1184     oop referent = java_lang_ref_Reference::referent(obj);
1185     if (PrintGCDetails) {
1186       gclog_or_tty->print_cr("Enqueued reference (" INTPTR_FORMAT ": %s)",
1187                              obj, obj->blueprint()->internal_name());
1188     }
1189     assert(referent->is_oop(), "Enqueued a bad referent");
1190   }
1191   assert(obj->is_oop(), "Enqueued a bad reference");
1192   return true;
1193 }
1194 
1195 // Preclean the discovered references by removing those
1196 // whose referents are alive, and by marking from those that
1197 // are not active. These lists can be handled here
1198 // in any order and, indeed, concurrently.
1199 void ReferenceProcessor::preclean_discovered_references(
1200   BoolObjectClosure* is_alive,
1201   OopClosure* keep_alive,
1202   VoidClosure* complete_gc,
1203   YieldClosure* yield) {
1204 
1205   NOT_PRODUCT(verify_ok_to_handle_reflists());
1206 
1207   // Soft references
1208   {
1209     TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
1210               false, gclog_or_tty);
1211     for (int i = 0; i < _num_q; i++) {



1212       preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive,
1213                                   keep_alive, complete_gc, yield);
1214     }
1215   }
1216   if (yield->should_return()) {
1217     return;
1218   }
1219 
1220   // Weak references
1221   {
1222     TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
1223               false, gclog_or_tty);
1224     for (int i = 0; i < _num_q; i++) {



1225       preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive,
1226                                   keep_alive, complete_gc, yield);
1227     }
1228   }
1229   if (yield->should_return()) {
1230     return;
1231   }
1232 
1233   // Final references
1234   {
1235     TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
1236               false, gclog_or_tty);
1237     for (int i = 0; i < _num_q; i++) {



1238       preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive,
1239                                   keep_alive, complete_gc, yield);
1240     }
1241   }
1242   if (yield->should_return()) {
1243     return;
1244   }
1245 
1246   // Phantom references
1247   {
1248     TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
1249               false, gclog_or_tty);
1250     for (int i = 0; i < _num_q; i++) {



1251       preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
1252                                   keep_alive, complete_gc, yield);
1253     }
1254   }
1255 }
1256 
1257 // Walk the given discovered ref list, and remove all reference objects
1258 // 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
1260 // correctly, refs discovery can not be happening concurrently with this
1261 // step.



1262 void
1263 ReferenceProcessor::preclean_discovered_reflist(DiscoveredList&    refs_list,
1264                                                 BoolObjectClosure* is_alive,
1265                                                 OopClosure*        keep_alive,
1266                                                 VoidClosure*       complete_gc,
1267                                                 YieldClosure*      yield) {
1268   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
1269   size_t length = refs_list.length();
1270   while (iter.has_next()) {
1271     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
1272     oop obj = iter.obj();
1273     oop next = java_lang_ref_Reference::next(obj);
1274     if (iter.referent() == NULL || iter.is_referent_alive() ||
1275         next != NULL) {
1276       // The referent has been cleared, or is alive, or the Reference is not
1277       // active; we need to trace and mark its cohort.
1278       if (TraceReferenceGC) {
1279         gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)",
1280                                iter.obj(), iter.obj()->blueprint()->internal_name());
1281       }
1282       // Remove Reference object from list
1283       iter.remove();
1284       --length;
1285       // Keep alive its cohort.
1286       iter.make_referent_alive();
1287       if (UseCompressedOops) {
1288         narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj);
1289         keep_alive->do_oop(next_addr);
1290       } else {
1291         oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj);
1292         keep_alive->do_oop(next_addr);
1293       }

1294     } else {
1295       iter.next();
1296     }
1297   }
1298   refs_list.set_length(length);
1299 
1300   // Close the reachable set
1301   complete_gc->do_void();
1302 
1303   NOT_PRODUCT(
1304     if (PrintGCDetails && PrintReferenceGC) {
1305       gclog_or_tty->print(" Dropped %d Refs out of %d "
1306         "Refs in discovered list ", iter.removed(), iter.processed());
1307     }
1308   )
1309 }
1310 
1311 const char* ReferenceProcessor::list_name(int i) {
1312    assert(i >= 0 && i <= _num_q * subclasses_of_ref, "Out of bounds index");
1313    int j = i / _num_q;
1314    switch (j) {
1315      case 0: return "SoftRef";
1316      case 1: return "WeakRef";
1317      case 2: return "FinalRef";
1318      case 3: return "PhantomRef";
1319    }




  31   DiscoveredList() : _len(0), _compressed_head(0), _oop_head(NULL) { }
  32   oop head() const     {
  33      return UseCompressedOops ?  oopDesc::decode_heap_oop_not_null(_compressed_head) :
  34                                 _oop_head;
  35   }
  36   HeapWord* adr_head() {
  37     return UseCompressedOops ? (HeapWord*)&_compressed_head :
  38                                (HeapWord*)&_oop_head;
  39   }
  40   void   set_head(oop o) {
  41     if (UseCompressedOops) {
  42       // Must compress the head ptr.
  43       _compressed_head = oopDesc::encode_heap_oop_not_null(o);
  44     } else {
  45       _oop_head = o;
  46     }
  47   }
  48   bool   empty() const          { return head() == ReferenceProcessor::sentinel_ref(); }
  49   size_t length()               { return _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; }
  53 private:
  54   // Set value depending on UseCompressedOops. This could be a template class
  55   // but then we have to fix all the instantiations and declarations that use this class.
  56   oop       _oop_head;
  57   narrowOop _compressed_head;
  58   size_t _len;
  59 };
  60 
  61 oop  ReferenceProcessor::_sentinelRef = NULL;
  62 
  63 const int subclasses_of_ref = REF_PHANTOM - REF_OTHER;
  64 
  65 void referenceProcessor_init() {
  66   ReferenceProcessor::init_statics();
  67 }
  68 
  69 void ReferenceProcessor::init_statics() {
  70   assert(_sentinelRef == NULL, "should be initialized precisely once");
  71   EXCEPTION_MARK;
  72   _sentinelRef = instanceKlass::cast(


 421   inline DiscoveredListIterator(DiscoveredList&    refs_list,
 422                                 OopClosure*        keep_alive,
 423                                 BoolObjectClosure* is_alive);
 424 
 425   // End Of List.
 426   inline bool has_next() const { return _next != ReferenceProcessor::sentinel_ref(); }
 427 
 428   // Get oop to the Reference object.
 429   inline oop obj() const { return _ref; }
 430 
 431   // Get oop to the referent object.
 432   inline oop referent() const { return _referent; }
 433 
 434   // Returns true if referent is alive.
 435   inline bool is_referent_alive() const;
 436 
 437   // Loads data for the current reference.
 438   // The "allow_null_referent" argument tells us to allow for the possibility
 439   // of a NULL referent in the discovered Reference object. This typically
 440   // happens in the case of concurrent collectors that may have done the
 441   // discovery concurrently, or interleaved, with mutator execution.
 442   inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
 443 
 444   // Move to the next discovered reference.
 445   inline void next();
 446 
 447   // Remove the current reference from the list
 448   inline void remove();
 449 
 450   // Make the Reference object active again.
 451   inline void make_active() { java_lang_ref_Reference::set_next(_ref, NULL); }
 452 
 453   // Make the referent alive.
 454   inline void make_referent_alive() {
 455     if (UseCompressedOops) {
 456       _keep_alive->do_oop((narrowOop*)_referent_addr);
 457     } else {
 458       _keep_alive->do_oop((oop*)_referent_addr);
 459     }
 460   }
 461 
 462   // Update the discovered field.
 463   inline void update_discovered() {
 464     // First _prev_next ref actually points into DiscoveredList (gross).
 465     if (UseCompressedOops) {
 466       _keep_alive->do_oop((narrowOop*)_prev_next);
 467     } else {
 468       _keep_alive->do_oop((oop*)_prev_next);
 469     }
 470   }
 471 
 472   // NULL out referent pointer.
 473   inline void clear_referent() { oop_store_raw(_referent_addr, NULL); }
 474 
 475   // Statistics
 476   NOT_PRODUCT(
 477   inline size_t processed() const { return _processed; }
 478   inline size_t removed() const   { return _removed; }
 479   )
 480 

 481   inline void move_to_next();
 482 
 483 private:
 484   DiscoveredList&    _refs_list;
 485   HeapWord*          _prev_next;
 486   oop                _ref;
 487   HeapWord*          _discovered_addr;
 488   oop                _next;
 489   HeapWord*          _referent_addr;
 490   oop                _referent;
 491   OopClosure*        _keep_alive;
 492   BoolObjectClosure* _is_alive;
 493   DEBUG_ONLY(
 494   oop                _first_seen; // cyclic linked list check
 495   )
 496   NOT_PRODUCT(
 497   size_t             _processed;
 498   size_t             _removed;
 499   )
 500 };


 537          "bad referent");
 538 }
 539 
 540 inline void DiscoveredListIterator::next() {
 541   _prev_next = _discovered_addr;
 542   move_to_next();
 543 }
 544 
 545 inline void DiscoveredListIterator::remove() {
 546   assert(_ref->is_oop(), "Dropping a bad reference");
 547   oop_store_raw(_discovered_addr, NULL);
 548   // First _prev_next ref actually points into DiscoveredList (gross).
 549   if (UseCompressedOops) {
 550     // Remove Reference object from list.
 551     oopDesc::encode_store_heap_oop_not_null((narrowOop*)_prev_next, _next);
 552   } else {
 553     // Remove Reference object from list.
 554     oopDesc::store_heap_oop((oop*)_prev_next, _next);
 555   }
 556   NOT_PRODUCT(_removed++);
 557   _refs_list.dec_length(1);
 558 }
 559 
 560 inline void DiscoveredListIterator::move_to_next() {
 561   _ref = _next;
 562   assert(_ref != _first_seen, "cyclic ref_list found");
 563   NOT_PRODUCT(_processed++);
 564 }
 565 
 566 // NOTE: process_phase*() are largely similar, and at a high level
 567 // merely iterate over the extant list applying a predicate to
 568 // each of its elements and possibly removing that element from the
 569 // list and applying some further closures to that element.
 570 // We should consider the possibility of replacing these
 571 // process_phase*() methods by abstracting them into
 572 // a single general iterator invocation that receives appropriate
 573 // closures that accomplish this work.
 574 
 575 // (SoftReferences only) Traverse the list and remove any SoftReferences whose
 576 // referents are not alive, but that should be kept alive for policy reasons.
 577 // Keep alive the transitive closure of all such referents.
 578 void
 579 ReferenceProcessor::process_phase1(DiscoveredList&    refs_list,
 580                                    ReferencePolicy*   policy,
 581                                    BoolObjectClosure* is_alive,
 582                                    OopClosure*        keep_alive,
 583                                    VoidClosure*       complete_gc) {
 584   assert(policy != NULL, "Must have a non-NULL policy");
 585   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 586   // Decide which softly reachable refs should be kept alive.
 587   while (iter.has_next()) {
 588     iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */));
 589     bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive();
 590     if (referent_is_dead && !policy->should_clear_reference(iter.obj())) {
 591       if (TraceReferenceGC) {
 592         gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s"  ") by policy",
 593                                iter.obj(), iter.obj()->blueprint()->internal_name());
 594       }
 595       // Remove Reference object from list
 596       iter.remove();
 597       // Make the Reference object active again
 598       iter.make_active();
 599       // keep the referent around
 600       iter.make_referent_alive();
 601       iter.move_to_next();

 602     } else {
 603       iter.next();
 604     }
 605   }
 606   // Close the reachable set
 607   complete_gc->do_void();
 608   NOT_PRODUCT(
 609     if (PrintGCDetails && TraceReferenceGC) {
 610       gclog_or_tty->print(" Dropped %d dead Refs out of %d "
 611         "discovered Refs by policy ", iter.removed(), iter.processed());
 612     }
 613   )
 614 }
 615 
 616 // Traverse the list and remove any Refs that are not active, or
 617 // whose referents are either alive or NULL.
 618 void
 619 ReferenceProcessor::pp2_work(DiscoveredList&    refs_list,
 620                              BoolObjectClosure* is_alive,
 621                              OopClosure*        keep_alive) {
 622   assert(discovery_is_atomic(), "Error");
 623   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 624   while (iter.has_next()) {
 625     iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));
 626     DEBUG_ONLY(oop next = java_lang_ref_Reference::next(iter.obj());)
 627     assert(next == NULL, "Should not discover inactive Reference");
 628     if (iter.is_referent_alive()) {
 629       if (TraceReferenceGC) {
 630         gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)",
 631                                iter.obj(), iter.obj()->blueprint()->internal_name());
 632       }
 633       // The referent is reachable after all.
 634       // Remove Reference object from list.
 635       iter.remove();
 636       // Update the referent pointer as necessary: Note that this
 637       // should not entail any recursive marking because the
 638       // referent must already have been traversed.
 639       iter.make_referent_alive();
 640       iter.move_to_next();

 641     } else {
 642       iter.next();
 643     }
 644   }
 645   NOT_PRODUCT(
 646     if (PrintGCDetails && TraceReferenceGC) {
 647       gclog_or_tty->print(" Dropped %d active Refs out of %d "
 648         "Refs in discovered list ", iter.removed(), iter.processed());
 649     }
 650   )
 651 }
 652 
 653 void
 654 ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList&    refs_list,
 655                                                   BoolObjectClosure* is_alive,
 656                                                   OopClosure*        keep_alive,
 657                                                   VoidClosure*       complete_gc) {
 658   assert(!discovery_is_atomic(), "Error");
 659   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
 660   while (iter.has_next()) {
 661     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
 662     HeapWord* next_addr = java_lang_ref_Reference::next_addr(iter.obj());
 663     oop next = java_lang_ref_Reference::next(iter.obj());
 664     if ((iter.referent() == NULL || iter.is_referent_alive() ||
 665          next != NULL)) {
 666       assert(next->is_oop_or_null(), "bad next field");
 667       // Remove Reference object from list
 668       iter.remove();
 669       // Trace the cohorts
 670       iter.make_referent_alive();
 671       if (UseCompressedOops) {
 672         keep_alive->do_oop((narrowOop*)next_addr);
 673       } else {
 674         keep_alive->do_oop((oop*)next_addr);
 675       }
 676       iter.move_to_next();
 677     } else {
 678       iter.next();
 679     }
 680   }
 681   // Now close the newly reachable set
 682   complete_gc->do_void();
 683   NOT_PRODUCT(
 684     if (PrintGCDetails && TraceReferenceGC) {
 685       gclog_or_tty->print(" Dropped %d active Refs out of %d "
 686         "Refs in discovered list ", iter.removed(), iter.processed());
 687     }
 688   )
 689 }
 690 
 691 // Traverse the list and process the referents, by either
 692 // clearing them or keeping them (and their reachable
 693 // closure) alive.
 694 void
 695 ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,
 696                                    bool               clear_referent,


 819   size_t avg_refs = total_refs / _num_q + 1;
 820   int to_idx = 0;
 821   for (int from_idx = 0; from_idx < _num_q; from_idx++) {
 822     while (ref_lists[from_idx].length() > avg_refs) {
 823       assert(to_idx < _num_q, "Sanity Check!");
 824       if (ref_lists[to_idx].length() < avg_refs) {
 825         // move superfluous refs
 826         size_t refs_to_move =
 827           MIN2(ref_lists[from_idx].length() - avg_refs,
 828                avg_refs - ref_lists[to_idx].length());
 829         oop move_head = ref_lists[from_idx].head();
 830         oop move_tail = move_head;
 831         oop new_head  = move_head;
 832         // find an element to split the list on
 833         for (size_t j = 0; j < refs_to_move; ++j) {
 834           move_tail = new_head;
 835           new_head = java_lang_ref_Reference::discovered(new_head);
 836         }
 837         java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head());
 838         ref_lists[to_idx].set_head(move_head);
 839         ref_lists[to_idx].inc_length(refs_to_move);
 840         ref_lists[from_idx].set_head(new_head);
 841         ref_lists[from_idx].dec_length(refs_to_move);
 842       } else {
 843         ++to_idx;
 844       }
 845     }
 846   }
 847 }
 848 
 849 void
 850 ReferenceProcessor::process_discovered_reflist(
 851   DiscoveredList               refs_lists[],
 852   ReferencePolicy*             policy,
 853   bool                         clear_referent,
 854   BoolObjectClosure*           is_alive,
 855   OopClosure*                  keep_alive,
 856   VoidClosure*                 complete_gc,
 857   AbstractRefProcTaskExecutor* task_executor)
 858 {
 859   bool mt = task_executor != NULL && _processing_is_mt;
 860   if (mt && ParallelRefProcBalancingEnabled) {
 861     balance_queues(refs_lists);


 910                      is_alive, keep_alive, complete_gc);
 911     }
 912   }
 913 }
 914 
 915 void ReferenceProcessor::clean_up_discovered_references() {
 916   // loop over the lists
 917   for (int i = 0; i < _num_q * subclasses_of_ref; i++) {
 918     if (TraceReferenceGC && PrintGCDetails && ((i % _num_q) == 0)) {
 919       gclog_or_tty->print_cr(
 920         "\nScrubbing %s discovered list of Null referents",
 921         list_name(i));
 922     }
 923     clean_up_discovered_reflist(_discoveredSoftRefs[i]);
 924   }
 925 }
 926 
 927 void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
 928   assert(!discovery_is_atomic(), "Else why call this method?");
 929   DiscoveredListIterator iter(refs_list, NULL, NULL);

 930   while (iter.has_next()) {
 931     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
 932     oop next = java_lang_ref_Reference::next(iter.obj());
 933     assert(next->is_oop_or_null(), "bad next field");
 934     // If referent has been cleared or Reference is not active,
 935     // drop it.
 936     if (iter.referent() == NULL || next != NULL) {
 937       debug_only(
 938         if (PrintGCDetails && TraceReferenceGC) {
 939           gclog_or_tty->print_cr("clean_up_discovered_list: Dropping Reference: "
 940             INTPTR_FORMAT " with next field: " INTPTR_FORMAT
 941             " and referent: " INTPTR_FORMAT,
 942             iter.obj(), next, iter.referent());
 943         }
 944       )
 945       // Remove Reference object from list
 946       iter.remove();
 947       iter.move_to_next();
 948     } else {
 949       iter.next();
 950     }
 951   }

 952   NOT_PRODUCT(
 953     if (PrintGCDetails && TraceReferenceGC) {
 954       gclog_or_tty->print(
 955         " Removed %d Refs with NULL referents out of %d discovered Refs",
 956         iter.removed(), iter.processed());
 957     }
 958   )
 959 }
 960 
 961 inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
 962   int id = 0;
 963   // Determine the queue index to use for this object.
 964   if (_discovery_is_mt) {
 965     // During a multi-threaded discovery phase,
 966     // each thread saves to its "own" list.
 967     Thread* thr = Thread::current();
 968     assert(thr->is_GC_task_thread(),
 969            "Dubious cast from Thread* to WorkerThread*?");
 970     id = ((WorkerThread*)thr)->id();
 971   } else {


1009                                               HeapWord*       discovered_addr) {
1010   assert(_discovery_is_mt, "!_discovery_is_mt should have been handled by caller");
1011   // First we must make sure this object is only enqueued once. CAS in a non null
1012   // discovered_addr.
1013   oop current_head = refs_list.head();
1014 
1015   // Note: In the case of G1, this pre-barrier is strictly
1016   // not necessary because the only case we are interested in
1017   // here is when *discovered_addr is NULL, so this will expand to
1018   // nothing. As a result, I am just manually eliding this out for G1.
1019   if (_discovered_list_needs_barrier && !UseG1GC) {
1020     _bs->write_ref_field_pre((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
1021   }
1022   oop retest = oopDesc::atomic_compare_exchange_oop(current_head, discovered_addr,
1023                                                     NULL);
1024   if (retest == NULL) {
1025     // This thread just won the right to enqueue the object.
1026     // We have separate lists for enqueueing so no synchronization
1027     // is necessary.
1028     refs_list.set_head(obj);
1029     refs_list.inc_length(1);
1030     if (_discovered_list_needs_barrier) {
1031       _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
1032     }
1033 
1034   } else {
1035     // If retest was non NULL, another thread beat us to it:
1036     // The reference has already been discovered...
1037     if (TraceReferenceGC) {
1038       gclog_or_tty->print_cr("Already enqueued reference (" INTPTR_FORMAT ": %s)",
1039                              obj, obj->blueprint()->internal_name());
1040     }
1041   }
1042 }
1043 
1044 // We mention two of several possible choices here:
1045 // #0: if the reference object is not in the "originating generation"
1046 //     (or part of the heap being collected, indicated by our "span"
1047 //     we don't treat it specially (i.e. we scan it as we would
1048 //     a normal oop, treating its references as strong references).
1049 //     This means that references can't be enqueued unless their


1153 
1154   if (_discovery_is_mt) {
1155     add_to_discovered_list_mt(*list, obj, discovered_addr);
1156   } else {
1157     // If "_discovered_list_needs_barrier", we do write barriers when
1158     // updating the discovered reference list.  Otherwise, we do a raw store
1159     // here: the field will be visited later when processing the discovered
1160     // references.
1161     oop current_head = list->head();
1162     // As in the case further above, since we are over-writing a NULL
1163     // pre-value, we can safely elide the pre-barrier here for the case of G1.
1164     assert(discovered == NULL, "control point invariant");
1165     if (_discovered_list_needs_barrier && !UseG1GC) { // safe to elide for G1
1166       _bs->write_ref_field_pre((oop*)discovered_addr, current_head);
1167     }
1168     oop_store_raw(discovered_addr, current_head);
1169     if (_discovered_list_needs_barrier) {
1170       _bs->write_ref_field((oop*)discovered_addr, current_head);
1171     }
1172     list->set_head(obj);
1173     list->inc_length(1);
1174   }
1175 
1176   // In the MT discovery case, it is currently possible to see
1177   // the following message multiple times if several threads
1178   // discover a reference about the same time. Only one will
1179   // however have actually added it to the disocvered queue.
1180   // One could let add_to_discovered_list_mt() return an
1181   // indication for success in queueing (by 1 thread) or
1182   // failure (by all other threads), but I decided the extra
1183   // code was not worth the effort for something that is
1184   // only used for debugging support.
1185   if (TraceReferenceGC) {
1186     oop referent = java_lang_ref_Reference::referent(obj);
1187     if (PrintGCDetails) {
1188       gclog_or_tty->print_cr("Enqueued reference (" INTPTR_FORMAT ": %s)",
1189                              obj, obj->blueprint()->internal_name());
1190     }
1191     assert(referent->is_oop(), "Enqueued a bad referent");
1192   }
1193   assert(obj->is_oop(), "Enqueued a bad reference");
1194   return true;
1195 }
1196 
1197 // Preclean the discovered references by removing those
1198 // whose referents are alive, and by marking from those that
1199 // are not active. These lists can be handled here
1200 // in any order and, indeed, concurrently.
1201 void ReferenceProcessor::preclean_discovered_references(
1202   BoolObjectClosure* is_alive,
1203   OopClosure* keep_alive,
1204   VoidClosure* complete_gc,
1205   YieldClosure* yield) {
1206 
1207   NOT_PRODUCT(verify_ok_to_handle_reflists());
1208 
1209   // Soft references
1210   {
1211     TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
1212               false, gclog_or_tty);
1213     for (int i = 0; i < _num_q; i++) {
1214       if (yield->should_return()) {
1215         return;
1216       }
1217       preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive,
1218                                   keep_alive, complete_gc, yield);
1219     }
1220   }



1221 
1222   // Weak references
1223   {
1224     TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
1225               false, gclog_or_tty);
1226     for (int i = 0; i < _num_q; i++) {
1227       if (yield->should_return()) {
1228         return;
1229       }
1230       preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive,
1231                                   keep_alive, complete_gc, yield);
1232     }
1233   }



1234 
1235   // Final references
1236   {
1237     TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
1238               false, gclog_or_tty);
1239     for (int i = 0; i < _num_q; i++) {
1240       if (yield->should_return()) {
1241         return;
1242       }
1243       preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive,
1244                                   keep_alive, complete_gc, yield);
1245     }
1246   }



1247 
1248   // Phantom references
1249   {
1250     TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
1251               false, gclog_or_tty);
1252     for (int i = 0; i < _num_q; i++) {
1253       if (yield->should_return()) {
1254         return;
1255       }
1256       preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
1257                                   keep_alive, complete_gc, yield);
1258     }
1259   }
1260 }
1261 
1262 // Walk the given discovered ref list, and remove all reference objects
1263 // whose referents are still alive, whose referents are NULL or which
1264 // are not active (have a non-NULL next field). NOTE: When we are
1265 // thus precleaning the ref lists (which happens single-threaded today),
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).
1270 void
1271 ReferenceProcessor::preclean_discovered_reflist(DiscoveredList&    refs_list,
1272                                                 BoolObjectClosure* is_alive,
1273                                                 OopClosure*        keep_alive,
1274                                                 VoidClosure*       complete_gc,
1275                                                 YieldClosure*      yield) {
1276   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);

1277   while (iter.has_next()) {
1278     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
1279     oop obj = iter.obj();
1280     oop next = java_lang_ref_Reference::next(obj);
1281     if (iter.referent() == NULL || iter.is_referent_alive() ||
1282         next != NULL) {
1283       // The referent has been cleared, or is alive, or the Reference is not
1284       // active; we need to trace and mark its cohort.
1285       if (TraceReferenceGC) {
1286         gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)",
1287                                iter.obj(), iter.obj()->blueprint()->internal_name());
1288       }
1289       // Remove Reference object from list
1290       iter.remove();

1291       // Keep alive its cohort.
1292       iter.make_referent_alive();
1293       if (UseCompressedOops) {
1294         narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj);
1295         keep_alive->do_oop(next_addr);
1296       } else {
1297         oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj);
1298         keep_alive->do_oop(next_addr);
1299       }
1300       iter.move_to_next();
1301     } else {
1302       iter.next();
1303     }
1304   }


1305   // Close the reachable set
1306   complete_gc->do_void();
1307 
1308   NOT_PRODUCT(
1309     if (PrintGCDetails && PrintReferenceGC) {
1310       gclog_or_tty->print(" Dropped %d Refs out of %d "
1311         "Refs in discovered list ", iter.removed(), iter.processed());
1312     }
1313   )
1314 }
1315 
1316 const char* ReferenceProcessor::list_name(int i) {
1317    assert(i >= 0 && i <= _num_q * subclasses_of_ref, "Out of bounds index");
1318    int j = i / _num_q;
1319    switch (j) {
1320      case 0: return "SoftRef";
1321      case 1: return "WeakRef";
1322      case 2: return "FinalRef";
1323      case 3: return "PhantomRef";
1324    }