diff src/share/vm/memory/referenceProcessor.hpp @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/memory/referenceProcessor.hpp	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,499 @@
+/*
+ * Copyright 2001-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+// ReferenceProcessor class encapsulates the per-"collector" processing
+// of "weak" references for GC. The interface is useful for supporting
+// a generational abstraction, in particular when there are multiple
+// generations that are being independently collected -- possibly
+// concurrently and/or incrementally.  Note, however, that the
+// ReferenceProcessor class abstracts away from a generational setting
+// by using only a heap interval (called "span" below), thus allowing
+// its use in a straightforward manner in a general, non-generational
+// setting.
+//
+// The basic idea is that each ReferenceProcessor object concerns
+// itself with ("weak") reference processing in a specific "span"
+// of the heap of interest to a specific collector. Currently,
+// the span is a convex interval of the heap, but, efficiency
+// apart, there seems to be no reason it couldn't be extended
+// (with appropriate modifications) to any "non-convex interval".
+
+// forward references
+class ReferencePolicy;
+class AbstractRefProcTaskExecutor;
+class DiscoveredList;
+
+class ReferenceProcessor : public CHeapObj {
+ friend class DiscoveredList;
+ friend class DiscoveredListIterator;
+ protected:
+  // End of list marker
+  static oop  _sentinelRef;
+  MemRegion   _span; // (right-open) interval of heap
+                     // subject to wkref discovery
+  bool        _discovering_refs;      // true when discovery enabled
+  bool        _discovery_is_atomic;   // if discovery is atomic wrt
+                                      // other collectors in configuration
+  bool        _discovery_is_mt;       // true if reference discovery is MT.
+  bool        _enqueuing_is_done;     // true if all weak references enqueued
+  bool        _processing_is_mt;      // true during phases when
+                                      // reference processing is MT.
+  int         _next_id;               // round-robin counter in
+                                      // support of work distribution
+
+  // For collectors that do not keep GC marking information
+  // in the object header, this field holds a closure that
+  // helps the reference processor determine the reachability
+  // of an oop (the field is currently initialized to NULL for
+  // all collectors but the CMS collector).
+  BoolObjectClosure* _is_alive_non_header;
+
+  // The discovered ref lists themselves
+  int             _num_q;       // the MT'ness degree of the queues below
+  DiscoveredList* _discoveredSoftRefs; // pointer to array of oops
+  DiscoveredList* _discoveredWeakRefs;
+  DiscoveredList* _discoveredFinalRefs;
+  DiscoveredList* _discoveredPhantomRefs;
+
+ public:
+  int  num_q()                           { return _num_q; }
+  DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; }
+  static oop* sentinel_ref()             { return &_sentinelRef; }
+
+ public:
+  // Process references with a certain reachability level.
+  void process_discovered_reflist(DiscoveredList               refs_lists[],
+                                  ReferencePolicy*             policy,
+                                  bool                         clear_referent,
+                                  BoolObjectClosure*           is_alive,
+                                  OopClosure*                  keep_alive,
+                                  VoidClosure*                 complete_gc,
+                                  AbstractRefProcTaskExecutor* task_executor);
+
+  void process_phaseJNI(BoolObjectClosure* is_alive,
+                        OopClosure*        keep_alive,
+                        VoidClosure*       complete_gc);
+
+  // Work methods used by the method process_discovered_reflist
+  // Phase1: keep alive all those referents that are otherwise
+  // dead but which must be kept alive by policy (and their closure).
+  void process_phase1(DiscoveredList&     refs_list_addr,
+                      ReferencePolicy*    policy,
+                      BoolObjectClosure*  is_alive,
+                      OopClosure*         keep_alive,
+                      VoidClosure*        complete_gc);
+  // Phase2: remove all those references whose referents are
+  // reachable.
+  inline void process_phase2(DiscoveredList&    refs_list_addr,
+                             BoolObjectClosure* is_alive,
+                             OopClosure*        keep_alive,
+                             VoidClosure*       complete_gc) {
+    if (discovery_is_atomic()) {
+      // complete_gc is ignored in this case for this phase
+      pp2_work(refs_list_addr, is_alive, keep_alive);
+    } else {
+      assert(complete_gc != NULL, "Error");
+      pp2_work_concurrent_discovery(refs_list_addr, is_alive,
+                                    keep_alive, complete_gc);
+    }
+  }
+  // Work methods in support of process_phase2
+  void pp2_work(DiscoveredList&    refs_list_addr,
+                BoolObjectClosure* is_alive,
+                OopClosure*        keep_alive);
+  void pp2_work_concurrent_discovery(
+                DiscoveredList&    refs_list_addr,
+                BoolObjectClosure* is_alive,
+                OopClosure*        keep_alive,
+                VoidClosure*       complete_gc);
+  // Phase3: process the referents by either clearing them
+  // or keeping them alive (and their closure)
+  void process_phase3(DiscoveredList&    refs_list_addr,
+                      bool               clear_referent,
+                      BoolObjectClosure* is_alive,
+                      OopClosure*        keep_alive,
+                      VoidClosure*       complete_gc);
+
+  // Enqueue references with a certain reachability level
+  void enqueue_discovered_reflist(DiscoveredList& refs_list, oop* pending_list_addr);
+
+  // "Preclean" all the discovered reference lists
+  // by removing references with strongly reachable referents.
+  // The first argument is a predicate on an oop that indicates
+  // its (strong) reachability and the second is a closure that
+  // may be used to incrementalize or abort the precleaning process.
+  // The caller is responsible for taking care of potential
+  // interference with concurrent operations on these lists
+  // (or predicates involved) by other threads. Currently
+  // only used by the CMS collector.
+  void preclean_discovered_references(BoolObjectClosure* is_alive,
+                                      OopClosure*        keep_alive,
+                                      VoidClosure*       complete_gc,
+                                      YieldClosure*      yield);
+
+  // Delete entries in the discovered lists that have
+  // either a null referent or are not active. Such
+  // Reference objects can result from the clearing
+  // or enqueueing of Reference objects concurrent
+  // with their discovery by a (concurrent) collector.
+  // For a definition of "active" see java.lang.ref.Reference;
+  // Refs are born active, become inactive when enqueued,
+  // and never become active again. The state of being
+  // active is encoded as follows: A Ref is active
+  // if and only if its "next" field is NULL.
+  void clean_up_discovered_references();
+  void clean_up_discovered_reflist(DiscoveredList& refs_list);
+
+  // Returns the name of the discovered reference list
+  // occupying the i / _num_q slot.
+  const char* list_name(int i);
+
+ protected:
+  // "Preclean" the given discovered reference list
+  // by removing references with strongly reachable referents.
+  // Currently used in support of CMS only.
+  void preclean_discovered_reflist(DiscoveredList&    refs_list,
+                                   BoolObjectClosure* is_alive,
+                                   OopClosure*        keep_alive,
+                                   VoidClosure*       complete_gc,
+                                   YieldClosure*      yield);
+
+  void enqueue_discovered_reflists(oop* pending_list_addr, AbstractRefProcTaskExecutor* task_executor);
+  int next_id() {
+    int id = _next_id;
+    if (++_next_id == _num_q) {
+      _next_id = 0;
+    }
+    return id;
+  }
+  DiscoveredList* get_discovered_list(ReferenceType rt);
+  inline void add_to_discovered_list_mt(DiscoveredList& refs_list, oop obj,
+                                        oop* discovered_addr);
+  void verify_ok_to_handle_reflists() PRODUCT_RETURN;
+
+  void abandon_partial_discovered_list(DiscoveredList& refs_list);
+  void abandon_partial_discovered_list_arr(DiscoveredList refs_lists[]);
+
+  // Calculate the number of jni handles.
+  unsigned int count_jni_refs();
+
+  // Balances reference queues.
+  void balance_queues(DiscoveredList ref_lists[]);
+
+  // Update (advance) the soft ref master clock field.
+  void update_soft_ref_master_clock();
+
+ public:
+  // constructor
+  ReferenceProcessor():
+    _span((HeapWord*)NULL, (HeapWord*)NULL),
+    _discoveredSoftRefs(NULL),  _discoveredWeakRefs(NULL),
+    _discoveredFinalRefs(NULL), _discoveredPhantomRefs(NULL),
+    _discovering_refs(false),
+    _discovery_is_atomic(true),
+    _enqueuing_is_done(false),
+    _discovery_is_mt(false),
+    _is_alive_non_header(NULL),
+    _num_q(0),
+    _processing_is_mt(false),
+    _next_id(0)
+  {}
+
+  ReferenceProcessor(MemRegion span, bool atomic_discovery,
+                     bool mt_discovery, int mt_degree = 1,
+                     bool mt_processing = false);
+
+  // Allocates and initializes a reference processor.
+  static ReferenceProcessor* create_ref_processor(
+    MemRegion          span,
+    bool               atomic_discovery,
+    bool               mt_discovery,
+    BoolObjectClosure* is_alive_non_header = NULL,
+    int                parallel_gc_threads = 1,
+    bool               mt_processing = false);
+
+  // RefDiscoveryPolicy values
+  enum {
+    ReferenceBasedDiscovery = 0,
+    ReferentBasedDiscovery  = 1
+  };
+
+  static void init_statics();
+
+ public:
+  // get and set "is_alive_non_header" field
+  BoolObjectClosure* is_alive_non_header() {
+    return _is_alive_non_header;
+  }
+  void set_is_alive_non_header(BoolObjectClosure* is_alive_non_header) {
+    _is_alive_non_header = is_alive_non_header;
+  }
+
+  // get and set span
+  MemRegion span()                   { return _span; }
+  void      set_span(MemRegion span) { _span = span; }
+
+  // start and stop weak ref discovery
+  void enable_discovery()   { _discovering_refs = true;  }
+  void disable_discovery()  { _discovering_refs = false; }
+  bool discovery_enabled()  { return _discovering_refs;  }
+
+  // whether discovery is atomic wrt other collectors
+  bool discovery_is_atomic() const { return _discovery_is_atomic; }
+  void set_atomic_discovery(bool atomic) { _discovery_is_atomic = atomic; }
+
+  // whether discovery is done by multiple threads same-old-timeously
+  bool discovery_is_mt() const { return _discovery_is_mt; }
+  void set_mt_discovery(bool mt) { _discovery_is_mt = mt; }
+
+  // Whether we are in a phase when _processing_ is MT.
+  bool processing_is_mt() const { return _processing_is_mt; }
+  void set_mt_processing(bool mt) { _processing_is_mt = mt; }
+
+  // whether all enqueuing of weak references is complete
+  bool enqueuing_is_done()  { return _enqueuing_is_done; }
+  void set_enqueuing_is_done(bool v) { _enqueuing_is_done = v; }
+
+  // iterate over oops
+  void weak_oops_do(OopClosure* f);       // weak roots
+  static void oops_do(OopClosure* f);     // strong root(s)
+
+  // Discover a Reference object, using appropriate discovery criteria
+  bool discover_reference(oop obj, ReferenceType rt);
+
+  // Process references found during GC (called by the garbage collector)
+  void process_discovered_references(ReferencePolicy*             policy,
+                                     BoolObjectClosure*           is_alive,
+                                     OopClosure*                  keep_alive,
+                                     VoidClosure*                 complete_gc,
+                                     AbstractRefProcTaskExecutor* task_executor);
+
+ public:
+  // Enqueue references at end of GC (called by the garbage collector)
+  bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL);
+
+  // debugging
+  void verify_no_references_recorded() PRODUCT_RETURN;
+  static void verify();
+
+  // clear the discovered lists (unlinking each entry).
+  void clear_discovered_references() PRODUCT_RETURN;
+};
+
+// A utility class to disable reference discovery in
+// the scope which contains it, for given ReferenceProcessor.
+class NoRefDiscovery: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  bool _was_discovering_refs;
+ public:
+  NoRefDiscovery(ReferenceProcessor* rp) : _rp(rp) {
+    if (_was_discovering_refs = _rp->discovery_enabled()) {
+      _rp->disable_discovery();
+    }
+  }
+
+  ~NoRefDiscovery() {
+    if (_was_discovering_refs) {
+      _rp->enable_discovery();
+    }
+  }
+};
+
+
+// A utility class to temporarily mutate the span of the
+// given ReferenceProcessor in the scope that contains it.
+class ReferenceProcessorSpanMutator: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  MemRegion           _saved_span;
+
+ public:
+  ReferenceProcessorSpanMutator(ReferenceProcessor* rp,
+                                MemRegion span):
+    _rp(rp) {
+    _saved_span = _rp->span();
+    _rp->set_span(span);
+  }
+
+  ~ReferenceProcessorSpanMutator() {
+    _rp->set_span(_saved_span);
+  }
+};
+
+// A utility class to temporarily change the MT'ness of
+// reference discovery for the given ReferenceProcessor
+// in the scope that contains it.
+class ReferenceProcessorMTMutator: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  bool                _saved_mt;
+
+ public:
+  ReferenceProcessorMTMutator(ReferenceProcessor* rp,
+                              bool mt):
+    _rp(rp) {
+    _saved_mt = _rp->discovery_is_mt();
+    _rp->set_mt_discovery(mt);
+  }
+
+  ~ReferenceProcessorMTMutator() {
+    _rp->set_mt_discovery(_saved_mt);
+  }
+};
+
+
+// A utility class to temporarily change the disposition
+// of the "is_alive_non_header" closure field of the
+// given ReferenceProcessor in the scope that contains it.
+class ReferenceProcessorIsAliveMutator: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  BoolObjectClosure*  _saved_cl;
+
+ public:
+  ReferenceProcessorIsAliveMutator(ReferenceProcessor* rp,
+                                   BoolObjectClosure*  cl):
+    _rp(rp) {
+    _saved_cl = _rp->is_alive_non_header();
+    _rp->set_is_alive_non_header(cl);
+  }
+
+  ~ReferenceProcessorIsAliveMutator() {
+    _rp->set_is_alive_non_header(_saved_cl);
+  }
+};
+
+// A utility class to temporarily change the disposition
+// of the "discovery_is_atomic" field of the
+// given ReferenceProcessor in the scope that contains it.
+class ReferenceProcessorAtomicMutator: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  bool                _saved_atomic_discovery;
+
+ public:
+  ReferenceProcessorAtomicMutator(ReferenceProcessor* rp,
+                                  bool atomic):
+    _rp(rp) {
+    _saved_atomic_discovery = _rp->discovery_is_atomic();
+    _rp->set_atomic_discovery(atomic);
+  }
+
+  ~ReferenceProcessorAtomicMutator() {
+    _rp->set_atomic_discovery(_saved_atomic_discovery);
+  }
+};
+
+
+// A utility class to temporarily change the MT processing
+// disposition of the given ReferenceProcessor instance
+// in the scope that contains it.
+class ReferenceProcessorMTProcMutator: StackObj {
+ private:
+  ReferenceProcessor* _rp;
+  bool  _saved_mt;
+
+ public:
+  ReferenceProcessorMTProcMutator(ReferenceProcessor* rp,
+                                  bool mt):
+    _rp(rp) {
+    _saved_mt = _rp->processing_is_mt();
+    _rp->set_mt_processing(mt);
+  }
+
+  ~ReferenceProcessorMTProcMutator() {
+    _rp->set_mt_processing(_saved_mt);
+  }
+};
+
+
+// This class is an interface used to implement task execution for the
+// reference processing.
+class AbstractRefProcTaskExecutor {
+public:
+
+  // Abstract tasks to execute.
+  class ProcessTask;
+  class EnqueueTask;
+
+  // Executes a task using worker threads.
+  virtual void execute(ProcessTask& task) = 0;
+  virtual void execute(EnqueueTask& task) = 0;
+
+  // Switch to single threaded mode.
+  virtual void set_single_threaded_mode() { };
+};
+
+// Abstract reference processing task to execute.
+class AbstractRefProcTaskExecutor::ProcessTask {
+protected:
+  ProcessTask(ReferenceProcessor& ref_processor,
+              DiscoveredList      refs_lists[],
+              bool                marks_oops_alive)
+    : _ref_processor(ref_processor),
+      _refs_lists(refs_lists),
+      _marks_oops_alive(marks_oops_alive)
+  { }
+
+public:
+  virtual void work(unsigned int work_id, BoolObjectClosure& is_alive,
+                    OopClosure& keep_alive,
+                    VoidClosure& complete_gc) = 0;
+
+  // Returns true if a task marks some oops as alive.
+  bool marks_oops_alive() const
+  { return _marks_oops_alive; }
+
+protected:
+  ReferenceProcessor& _ref_processor;
+  DiscoveredList*     _refs_lists;
+  const bool          _marks_oops_alive;
+};
+
+// Abstract reference processing task to execute.
+class AbstractRefProcTaskExecutor::EnqueueTask {
+protected:
+  EnqueueTask(ReferenceProcessor& ref_processor,
+              DiscoveredList      refs_lists[],
+              oop*                pending_list_addr,
+              oop                 sentinel_ref,
+              int                 n_queues)
+    : _ref_processor(ref_processor),
+      _refs_lists(refs_lists),
+      _pending_list_addr(pending_list_addr),
+      _sentinel_ref(sentinel_ref),
+      _n_queues(n_queues)
+  { }
+
+public:
+  virtual void work(unsigned int work_id) = 0;
+
+protected:
+  ReferenceProcessor& _ref_processor;
+  DiscoveredList*     _refs_lists;
+  oop*                _pending_list_addr;
+  oop                 _sentinel_ref;
+  int                 _n_queues;
+};