#ifdef USE_PRAGMA_IDENT_HDR
#pragma ident "@(#)cmsOopClosures.hpp	1.4 08/09/25 13:46:14 JVM"
#endif
/*
 * Copyright (c) 2008 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.
 *  
 */

/////////////////////////////////////////////////////////////////
// Closures used by ConcurrentMarkSweepGeneration's collector
/////////////////////////////////////////////////////////////////
class ConcurrentMarkSweepGeneration;
class CMSBitMap;
class CMSMarkStack;
class CMSCollector;
template<class E> class GenericTaskQueue;
typedef GenericTaskQueue<oop> OopTaskQueue;
template<class E> class GenericTaskQueueSet;
typedef GenericTaskQueueSet<oop> OopTaskQueueSet;
class MarkFromRootsClosure;
class Par_MarkFromRootsClosure;

class MarkRefsIntoClosure: public OopsInGenClosure {
  const MemRegion    _span;
  CMSBitMap*         _bitMap;
  const bool         _should_do_nmethods;
 public:
  MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap,
                      bool should_do_nmethods);
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { MarkRefsIntoClosure::do_oop(p); }
  bool do_header() { return true; }
  virtual const bool do_nmethods() const {
    return _should_do_nmethods;
  }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
};

// A variant of the above used in certain kinds of CMS
// marking verification.
class MarkRefsIntoVerifyClosure: public OopsInGenClosure {
  const MemRegion    _span;
  CMSBitMap*         _verification_bm;
  CMSBitMap*         _cms_bm;
  const bool         _should_do_nmethods;
 public:
  MarkRefsIntoVerifyClosure(MemRegion span, CMSBitMap* verification_bm,
                            CMSBitMap* cms_bm, bool should_do_nmethods);
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { MarkRefsIntoVerifyClosure::do_oop(p); }
  bool do_header() { return true; }
  virtual const bool do_nmethods() const {
    return _should_do_nmethods;
  }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
};


// The non-parallel version (the parallel version appears further below).
class PushAndMarkClosure: public OopClosure {
  CMSCollector*    _collector;
  MemRegion        _span;
  CMSBitMap*       _bit_map;
  CMSBitMap*       _mod_union_table;
  CMSMarkStack*    _mark_stack;
  CMSMarkStack*    _revisit_stack;
  bool             _concurrent_precleaning;
  bool     const   _should_remember_klasses;
 public:
  PushAndMarkClosure(CMSCollector* collector,
                     MemRegion span,
                     ReferenceProcessor* rp,
                     CMSBitMap* bit_map,
                     CMSBitMap* mod_union_table,
                     CMSMarkStack*  mark_stack,
                     CMSMarkStack*  revisit_stack,
                     bool           concurrent_precleaning);

  void do_oop(oop* p);    
  void do_oop_nv(oop* p)  { PushAndMarkClosure::do_oop(p); }
  bool do_header() { return true; }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
  const bool should_remember_klasses() const {
    return _should_remember_klasses;
  }
  void remember_klass(Klass* k);
};

// In the parallel case, the revisit stack, the bit map and the
// reference processor are currently all shared. Access to
// these shared mutable structures must use appropriate
// synchronization (for instance, via CAS). The marking stack
// used in the non-parallel case above is here replaced with
// an OopTaskQueue structure to allow efficient work stealing.
class Par_PushAndMarkClosure: public OopClosure {
  CMSCollector*    _collector;
  MemRegion        _span;
  CMSBitMap*       _bit_map;
  OopTaskQueue*    _work_queue;
  CMSMarkStack*    _revisit_stack;
  bool     const   _should_remember_klasses;
 public:
  Par_PushAndMarkClosure(CMSCollector* collector,
                         MemRegion span,
                         ReferenceProcessor* rp,
                         CMSBitMap* bit_map,
                         OopTaskQueue* work_queue,
                         CMSMarkStack* revisit_stack);

  void do_oop(oop* p);
  void do_oop_nv(oop* p)  { Par_PushAndMarkClosure::do_oop(p); }
  bool do_header() { return true; }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
  const bool should_remember_klasses() const {
    return _should_remember_klasses;
  }
  void remember_klass(Klass* k);
};


// The non-parallel version (the parallel version appears further below).
class MarkRefsIntoAndScanClosure: public OopsInGenClosure {
  MemRegion                  _span;
  CMSBitMap*                 _bit_map;
  CMSMarkStack*              _mark_stack;
  PushAndMarkClosure         _pushAndMarkClosure;
  CMSCollector*              _collector;
  bool                       _yield;
  // Whether closure is being used for concurrent precleaning
  bool                       _concurrent_precleaning;
  Mutex*                     _freelistLock;
 public:
  MarkRefsIntoAndScanClosure(MemRegion span,
                             ReferenceProcessor* rp,
                             CMSBitMap* bit_map,
                             CMSBitMap* mod_union_table,
                             CMSMarkStack*  mark_stack,
                             CMSMarkStack*  revisit_stack,
                             CMSCollector* collector,
                             bool should_yield,
                             bool concurrent_precleaning);
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop(p); }
  bool do_header() { return true; }
  virtual const bool do_nmethods() const { return true; }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
  void set_freelistLock(Mutex* m) {
    _freelistLock = m;
  }

 private:
  inline void do_yield_check();
  void do_yield_work();
  bool take_from_overflow_list();
};

// Tn this, the parallel avatar of MarkRefsIntoAndScanClosure, the revisit
// stack and the bitMap are shared, so access needs to be suitably
// sycnhronized. An OopTaskQueue structure, supporting efficient
// workstealing, replaces a CMSMarkStack for storing grey objects.
class Par_MarkRefsIntoAndScanClosure: public OopsInGenClosure {
  MemRegion                      _span;
  CMSBitMap*                     _bit_map;
  OopTaskQueue*                  _work_queue;
  const uint                     _low_water_mark;
  Par_PushAndMarkClosure         _par_pushAndMarkClosure;
 public:
  Par_MarkRefsIntoAndScanClosure(CMSCollector* collector,
                                 MemRegion span,
                                 ReferenceProcessor* rp,
                                 CMSBitMap* bit_map,
                                 OopTaskQueue* work_queue,
                                 CMSMarkStack*  revisit_stack);
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { Par_MarkRefsIntoAndScanClosure::do_oop(p); }
  bool do_header() { return true; }
  virtual const bool do_nmethods() const { return true; }
  Prefetch::style prefetch_style() {
    return Prefetch::do_read;
  }
  void trim_queue(uint size);
};

// This closure is used during the concurrent marking phase
// following the first checkpoint. Its use is buried in
// the closure MarkFromRootsClosure.
class PushOrMarkClosure: public OopClosure {
  CMSCollector*    _collector;
  MemRegion        _span;
  CMSBitMap*       _bitMap;
  CMSMarkStack*    _markStack;
  CMSMarkStack*    _revisitStack;
  HeapWord* const  _finger;
  MarkFromRootsClosure* const _parent;
  bool                  const _should_remember_klasses;
 public:
  PushOrMarkClosure(CMSCollector* cms_collector,
                    MemRegion span,
                    CMSBitMap* bitMap,
                    CMSMarkStack*  markStack,
                    CMSMarkStack*  revisitStack,
                    HeapWord*      finger,
                    MarkFromRootsClosure* parent);
  void do_oop(oop* p);
  void do_oop_nv(oop* p)  { PushOrMarkClosure::do_oop(p); }
  const bool should_remember_klasses() const {
    return _should_remember_klasses;
  }
  void remember_klass(Klass* k);
  // Deal with a stack overflow condition
  void handle_stack_overflow(HeapWord* lost);
 private:
  inline void do_yield_check();
};

// A parallel (MT) version of the above.
// This closure is used during the concurrent marking phase
// following the first checkpoint. Its use is buried in
// the closure Par_MarkFromRootsClosure.
class Par_PushOrMarkClosure: public OopClosure {
  CMSCollector*    _collector;
  MemRegion        _whole_span;
  MemRegion        _span;        // local chunk
  CMSBitMap*       _bit_map;
  OopTaskQueue*    _work_queue;
  CMSMarkStack*    _overflow_stack;
  CMSMarkStack*    _revisit_stack;
  HeapWord*  const _finger;
  HeapWord** const _global_finger_addr;
  Par_MarkFromRootsClosure* const _parent;
  bool       const _should_remember_klasses;
 public:
  Par_PushOrMarkClosure(CMSCollector* cms_collector,
                    MemRegion span,
                    CMSBitMap* bit_map,
                    OopTaskQueue* work_queue,
                    CMSMarkStack*  mark_stack,
                    CMSMarkStack*  revisit_stack,
                    HeapWord*      finger,
                    HeapWord**     global_finger_addr,
                    Par_MarkFromRootsClosure* parent);
  void do_oop(oop* p);
  void do_oop_nv(oop* p)  { Par_PushOrMarkClosure::do_oop(p); }
  const bool should_remember_klasses() const {
    return _should_remember_klasses;
  }
  void remember_klass(Klass* k);
  // Deal with a stack overflow condition
  void handle_stack_overflow(HeapWord* lost);
 private:
  inline void do_yield_check();
};

// For objects in CMS generation, this closure marks
// given objects (transitively) as being reachable/live.
// This is currently used during the (weak) reference object
// processing phase of the CMS final checkpoint step.
class CMSKeepAliveClosure: public OopClosure {
  CMSCollector* _collector;
  const MemRegion _span;
  CMSMarkStack* _mark_stack;
  CMSBitMap*    _bit_map;
 public:
  CMSKeepAliveClosure(CMSCollector* collector, MemRegion span,
                      CMSBitMap* bit_map, CMSMarkStack* mark_stack):
    _collector(collector),
    _span(span),
    _bit_map(bit_map),
    _mark_stack(mark_stack) { 
      assert(!_span.is_empty(), "Empty span could spell trouble");
    }

  void do_oop(oop* p);
  void do_oop_nv(oop* p) { CMSKeepAliveClosure::do_oop(p); }
};

class CMSInnerParMarkAndPushClosure: public OopClosure {
  CMSCollector* _collector;
  MemRegion     _span;
  OopTaskQueue* _work_queue;
  CMSBitMap*    _bit_map;
 public:
  CMSInnerParMarkAndPushClosure(CMSCollector* collector,
                                MemRegion span, CMSBitMap* bit_map,
                                OopTaskQueue* work_queue):
    _collector(collector),
    _span(span),
    _bit_map(bit_map),
    _work_queue(work_queue) { }
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { CMSInnerParMarkAndPushClosure::do_oop(p); }
};

// A parallel (MT) version of the above, used when
// reference processing is parallel; the only difference
// is in the do_oop method.
class CMSParKeepAliveClosure: public OopClosure {
  CMSCollector* _collector;
  MemRegion     _span;
  OopTaskQueue* _work_queue;
  CMSBitMap*    _bit_map;
  CMSInnerParMarkAndPushClosure _mark_and_push;
  const uint    _low_water_mark;
  void trim_queue(uint max);
 public:
  CMSParKeepAliveClosure(CMSCollector* collector, MemRegion span,
                         CMSBitMap* bit_map, OopTaskQueue* work_queue);
  void do_oop(oop* p);
  void do_oop_nv(oop* p) { CMSParKeepAliveClosure::do_oop(p); }
};
