Merge

Mon, 09 Mar 2009 11:32:57 -0400

author
tonyp
date
Mon, 09 Mar 2009 11:32:57 -0400
changeset 1055
bcedf688d882
parent 1049
3db67f76d308
parent 1054
7ea5ca260b28
child 1060
2f2f54ed12ce
child 1061
87fa6e083d82

Merge

src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/os.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Thu Mar 05 22:07:29 2009 -0500
     1.2 +++ b/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Mon Mar 09 11:32:57 2009 -0400
     1.3 @@ -133,14 +133,12 @@
     1.4        _co_tracker.update(false);
     1.5  
     1.6        if (G1SmoothConcRefine) {
     1.7 -        start_vtime_sec = os::elapsedVTime();
     1.8          prev_buffer_num = curr_buffer_num;
     1.9 -
    1.10          _sts.leave();
    1.11          os::sleep(Thread::current(), (jlong) _interval_ms, false);
    1.12          _sts.join();
    1.13 +        start_vtime_sec = os::elapsedVTime();
    1.14        }
    1.15 -
    1.16        n_logs++;
    1.17      }
    1.18      // Make sure we harvest the PYA, if any.
     2.1 --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Mar 05 22:07:29 2009 -0500
     2.2 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Mon Mar 09 11:32:57 2009 -0400
     2.3 @@ -420,6 +420,10 @@
     2.4  
     2.5    _has_overflown(false),
     2.6    _concurrent(false),
     2.7 +  _has_aborted(false),
     2.8 +  _restart_for_overflow(false),
     2.9 +  _concurrent_marking_in_progress(false),
    2.10 +  _should_gray_objects(false),
    2.11  
    2.12    // _verbose_level set below
    2.13  
     3.1 --- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Thu Mar 05 22:07:29 2009 -0500
     3.2 +++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Mon Mar 09 11:32:57 2009 -0400
     3.3 @@ -107,7 +107,7 @@
     3.4        if (PrintGC) {
     3.5          gclog_or_tty->date_stamp(PrintGCDateStamps);
     3.6          gclog_or_tty->stamp(PrintGCTimeStamps);
     3.7 -        tty->print_cr("[GC concurrent-mark-start]");
     3.8 +        gclog_or_tty->print_cr("[GC concurrent-mark-start]");
     3.9        }
    3.10  
    3.11        if (!g1_policy->in_young_gc_mode()) {
    3.12 @@ -320,8 +320,6 @@
    3.13    set_in_progress();
    3.14    clear_started();
    3.15    if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-starting");
    3.16 -
    3.17 -  return;
    3.18  }
    3.19  
    3.20  // Note: this method, although exported by the ConcurrentMarkSweepThread,
     4.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp	Thu Mar 05 22:07:29 2009 -0500
     4.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp	Mon Mar 09 11:32:57 2009 -0400
     4.3 @@ -78,8 +78,8 @@
     4.4  
     4.5  void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
     4.6                                     int max_completed_queue,
     4.7 -                                   Mutex* lock) {
     4.8 -  PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue);
     4.9 +                                   Mutex* lock, PtrQueueSet* fl_owner) {
    4.10 +  PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner);
    4.11    set_buffer_size(DCQBarrierQueueBufferSize);
    4.12    set_process_completed_threshold(DCQBarrierProcessCompletedThreshold);
    4.13  
     5.1 --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp	Thu Mar 05 22:07:29 2009 -0500
     5.2 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp	Mon Mar 09 11:32:57 2009 -0400
     5.3 @@ -88,7 +88,7 @@
     5.4  
     5.5    void initialize(Monitor* cbl_mon, Mutex* fl_lock,
     5.6                    int max_completed_queue = 0,
     5.7 -                  Mutex* lock = NULL);
     5.8 +                  Mutex* lock = NULL, PtrQueueSet* fl_owner = NULL);
     5.9  
    5.10    // The number of parallel ids that can be claimed to allow collector or
    5.11    // mutator threads to do card-processing work.
     6.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Mar 05 22:07:29 2009 -0500
     6.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Mar 09 11:32:57 2009 -0400
     6.3 @@ -136,6 +136,14 @@
     6.4    int calls() { return _calls; }
     6.5  };
     6.6  
     6.7 +class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure {
     6.8 +public:
     6.9 +  bool do_card_ptr(jbyte* card_ptr, int worker_i) {
    6.10 +    *card_ptr = CardTableModRefBS::dirty_card_val();
    6.11 +    return true;
    6.12 +  }
    6.13 +};
    6.14 +
    6.15  YoungList::YoungList(G1CollectedHeap* g1h)
    6.16    : _g1h(g1h), _head(NULL),
    6.17      _scan_only_head(NULL), _scan_only_tail(NULL), _curr_scan_only(NULL),
    6.18 @@ -961,7 +969,8 @@
    6.19      // dirtied, so this should abandon those logs, and set "do_traversal"
    6.20      // to true.
    6.21      concurrent_g1_refine()->set_pya_restart();
    6.22 -
    6.23 +    assert(!G1DeferredRSUpdate
    6.24 +           || (G1DeferredRSUpdate && (dirty_card_queue_set().completed_buffers_num() == 0)), "Should not be any");
    6.25      assert(regions_accounted_for(), "Region leakage!");
    6.26    }
    6.27  
    6.28 @@ -1466,6 +1475,13 @@
    6.29                                                    G1DirtyCardQueueMax,
    6.30                                                    Shared_DirtyCardQ_lock);
    6.31    }
    6.32 +  if (G1DeferredRSUpdate) {
    6.33 +    dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
    6.34 +                                      DirtyCardQ_FL_lock,
    6.35 +                                      0,
    6.36 +                                      Shared_DirtyCardQ_lock,
    6.37 +                                      &JavaThread::dirty_card_queue_set());
    6.38 +  }
    6.39    // In case we're keeping closure specialization stats, initialize those
    6.40    // counts and that mechanism.
    6.41    SpecializationStats::clear();
    6.42 @@ -2316,7 +2332,6 @@
    6.43  void
    6.44  G1CollectedHeap::checkConcurrentMark() {
    6.45      VerifyMarkedObjsClosure verifycl(this);
    6.46 -    doConcurrentMark();
    6.47      //    MutexLockerEx x(getMarkBitMapLock(),
    6.48      //              Mutex::_no_safepoint_check_flag);
    6.49      object_iterate(&verifycl);
    6.50 @@ -2493,7 +2508,7 @@
    6.51  
    6.52      guarantee(_in_cset_fast_test == NULL, "invariant");
    6.53      guarantee(_in_cset_fast_test_base == NULL, "invariant");
    6.54 -    _in_cset_fast_test_length = n_regions();
    6.55 +    _in_cset_fast_test_length = max_regions();
    6.56      _in_cset_fast_test_base =
    6.57                               NEW_C_HEAP_ARRAY(bool, _in_cset_fast_test_length);
    6.58      memset(_in_cset_fast_test_base, false,
    6.59 @@ -2918,27 +2933,51 @@
    6.60    }
    6.61  };
    6.62  
    6.63 -class RecreateRSetEntriesClosure: public OopClosure {
    6.64 +class UpdateRSetImmediate : public OopsInHeapRegionClosure {
    6.65  private:
    6.66    G1CollectedHeap* _g1;
    6.67    G1RemSet* _g1_rem_set;
    6.68 -  HeapRegion* _from;
    6.69  public:
    6.70 -  RecreateRSetEntriesClosure(G1CollectedHeap* g1, HeapRegion* from) :
    6.71 -    _g1(g1), _g1_rem_set(g1->g1_rem_set()), _from(from)
    6.72 -  {}
    6.73 +  UpdateRSetImmediate(G1CollectedHeap* g1) :
    6.74 +    _g1(g1), _g1_rem_set(g1->g1_rem_set()) {}
    6.75  
    6.76    void do_oop(narrowOop* p) {
    6.77      guarantee(false, "NYI");
    6.78    }
    6.79    void do_oop(oop* p) {
    6.80      assert(_from->is_in_reserved(p), "paranoia");
    6.81 -    if (*p != NULL) {
    6.82 -      _g1_rem_set->write_ref(_from, p);
    6.83 +    if (*p != NULL && !_from->is_survivor()) {
    6.84 +      _g1_rem_set->par_write_ref(_from, p, 0);
    6.85      }
    6.86    }
    6.87  };
    6.88  
    6.89 +class UpdateRSetDeferred : public OopsInHeapRegionClosure {
    6.90 +private:
    6.91 +  G1CollectedHeap* _g1;
    6.92 +  DirtyCardQueue *_dcq;
    6.93 +  CardTableModRefBS* _ct_bs;
    6.94 +
    6.95 +public:
    6.96 +  UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) :
    6.97 +    _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {}
    6.98 +
    6.99 +  void do_oop(narrowOop* p) {
   6.100 +    guarantee(false, "NYI");
   6.101 +  }
   6.102 +  void do_oop(oop* p) {
   6.103 +    assert(_from->is_in_reserved(p), "paranoia");
   6.104 +    if (!_from->is_in_reserved(*p) && !_from->is_survivor()) {
   6.105 +      size_t card_index = _ct_bs->index_for(p);
   6.106 +      if (_ct_bs->mark_card_deferred(card_index)) {
   6.107 +        _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
   6.108 +      }
   6.109 +    }
   6.110 +  }
   6.111 +};
   6.112 +
   6.113 +
   6.114 +
   6.115  class RemoveSelfPointerClosure: public ObjectClosure {
   6.116  private:
   6.117    G1CollectedHeap* _g1;
   6.118 @@ -2946,11 +2985,11 @@
   6.119    HeapRegion* _hr;
   6.120    size_t _prev_marked_bytes;
   6.121    size_t _next_marked_bytes;
   6.122 +  OopsInHeapRegionClosure *_cl;
   6.123  public:
   6.124 -  RemoveSelfPointerClosure(G1CollectedHeap* g1, HeapRegion* hr) :
   6.125 -    _g1(g1), _cm(_g1->concurrent_mark()), _hr(hr),
   6.126 -    _prev_marked_bytes(0), _next_marked_bytes(0)
   6.127 -  {}
   6.128 +  RemoveSelfPointerClosure(G1CollectedHeap* g1, OopsInHeapRegionClosure* cl) :
   6.129 +    _g1(g1), _cm(_g1->concurrent_mark()),  _prev_marked_bytes(0),
   6.130 +    _next_marked_bytes(0), _cl(cl) {}
   6.131  
   6.132    size_t prev_marked_bytes() { return _prev_marked_bytes; }
   6.133    size_t next_marked_bytes() { return _next_marked_bytes; }
   6.134 @@ -2988,8 +3027,7 @@
   6.135        // that, if evacuation fails, we might have remembered set
   6.136        // entries missing given that we skipped cards on the
   6.137        // collection set. So, we'll recreate such entries now.
   6.138 -      RecreateRSetEntriesClosure cl(_g1, _hr);
   6.139 -      obj->oop_iterate(&cl);
   6.140 +      obj->oop_iterate(_cl);
   6.141        assert(_cm->isPrevMarked(obj), "Should be marked!");
   6.142      } else {
   6.143        // The object has been either evacuated or is dead. Fill it with a
   6.144 @@ -3002,14 +3040,23 @@
   6.145  };
   6.146  
   6.147  void G1CollectedHeap::remove_self_forwarding_pointers() {
   6.148 +  UpdateRSetImmediate immediate_update(_g1h);
   6.149 +  DirtyCardQueue dcq(&_g1h->dirty_card_queue_set());
   6.150 +  UpdateRSetDeferred deferred_update(_g1h, &dcq);
   6.151 +  OopsInHeapRegionClosure *cl;
   6.152 +  if (G1DeferredRSUpdate) {
   6.153 +    cl = &deferred_update;
   6.154 +  } else {
   6.155 +    cl = &immediate_update;
   6.156 +  }
   6.157    HeapRegion* cur = g1_policy()->collection_set();
   6.158 -
   6.159    while (cur != NULL) {
   6.160      assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!");
   6.161  
   6.162 +    RemoveSelfPointerClosure rspc(_g1h, cl);
   6.163      if (cur->evacuation_failed()) {
   6.164 -      RemoveSelfPointerClosure rspc(_g1h, cur);
   6.165        assert(cur->in_collection_set(), "bad CS");
   6.166 +      cl->set_region(cur);
   6.167        cur->object_iterate(&rspc);
   6.168  
   6.169        // A number of manipulations to make the TAMS be the current top,
   6.170 @@ -3518,6 +3565,9 @@
   6.171  protected:
   6.172    G1CollectedHeap* _g1h;
   6.173    RefToScanQueue*  _refs;
   6.174 +  DirtyCardQueue   _dcq;
   6.175 +  CardTableModRefBS* _ct_bs;
   6.176 +  G1RemSet* _g1_rem;
   6.177  
   6.178    typedef GrowableArray<oop*> OverflowQueue;
   6.179    OverflowQueue* _overflowed_refs;
   6.180 @@ -3559,10 +3609,32 @@
   6.181  
   6.182    void   add_to_undo_waste(size_t waste)         { _undo_waste += waste; }
   6.183  
   6.184 +  DirtyCardQueue& dirty_card_queue()             { return _dcq;  }
   6.185 +  CardTableModRefBS* ctbs()                      { return _ct_bs; }
   6.186 +
   6.187 +  void immediate_rs_update(HeapRegion* from, oop* p, int tid) {
   6.188 +    _g1_rem->par_write_ref(from, p, tid);
   6.189 +  }
   6.190 +
   6.191 +  void deferred_rs_update(HeapRegion* from, oop* p, int tid) {
   6.192 +    // If the new value of the field points to the same region or
   6.193 +    // is the to-space, we don't need to include it in the Rset updates.
   6.194 +    if (!from->is_in_reserved(*p) && !from->is_survivor()) {
   6.195 +      size_t card_index = ctbs()->index_for(p);
   6.196 +      // If the card hasn't been added to the buffer, do it.
   6.197 +      if (ctbs()->mark_card_deferred(card_index)) {
   6.198 +        dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index));
   6.199 +      }
   6.200 +    }
   6.201 +  }
   6.202 +
   6.203  public:
   6.204    G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num)
   6.205      : _g1h(g1h),
   6.206        _refs(g1h->task_queue(queue_num)),
   6.207 +      _dcq(&g1h->dirty_card_queue_set()),
   6.208 +      _ct_bs((CardTableModRefBS*)_g1h->barrier_set()),
   6.209 +      _g1_rem(g1h->g1_rem_set()),
   6.210        _hash_seed(17), _queue_num(queue_num),
   6.211        _term_attempts(0),
   6.212        _age_table(false),
   6.213 @@ -3640,6 +3712,14 @@
   6.214    int refs_to_scan()                             { return refs()->size();                 }
   6.215    int overflowed_refs_to_scan()                  { return overflowed_refs()->length();    }
   6.216  
   6.217 +  void update_rs(HeapRegion* from, oop* p, int tid) {
   6.218 +    if (G1DeferredRSUpdate) {
   6.219 +      deferred_rs_update(from, p, tid);
   6.220 +    } else {
   6.221 +      immediate_rs_update(from, p, tid);
   6.222 +    }
   6.223 +  }
   6.224 +
   6.225    HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) {
   6.226  
   6.227      HeapWord* obj = NULL;
   6.228 @@ -3808,7 +3888,6 @@
   6.229    }
   6.230  };
   6.231  
   6.232 -
   6.233  G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
   6.234    _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()),
   6.235    _par_scan_state(par_scan_state) { }
   6.236 @@ -3834,7 +3913,7 @@
   6.237        assert(obj == *p, "the value of *p should not have changed");
   6.238        _par_scan_state->push_on_queue(p);
   6.239      } else {
   6.240 -      _g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
   6.241 +      _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
   6.242      }
   6.243    }
   6.244  }
   6.245 @@ -3972,13 +4051,13 @@
   6.246      }
   6.247      // When scanning the RS, we only care about objs in CS.
   6.248      if (barrier == G1BarrierRS) {
   6.249 -      _g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
   6.250 +      _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
   6.251      }
   6.252    }
   6.253  
   6.254    // When scanning moved objs, must look at all oops.
   6.255    if (barrier == G1BarrierEvac && obj != NULL) {
   6.256 -    _g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
   6.257 +    _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
   6.258    }
   6.259  
   6.260    if (do_gen_barrier && obj != NULL) {
   6.261 @@ -4127,6 +4206,7 @@
   6.262      G1ParScanExtRootClosure         only_scan_root_cl(_g1h, &pss);
   6.263      G1ParScanPermClosure            only_scan_perm_cl(_g1h, &pss);
   6.264      G1ParScanHeapRSClosure          only_scan_heap_rs_cl(_g1h, &pss);
   6.265 +
   6.266      G1ParScanAndMarkExtRootClosure  scan_mark_root_cl(_g1h, &pss);
   6.267      G1ParScanAndMarkPermClosure     scan_mark_perm_cl(_g1h, &pss);
   6.268      G1ParScanAndMarkHeapRSClosure   scan_mark_heap_rs_cl(_g1h, &pss);
   6.269 @@ -4382,7 +4462,6 @@
   6.270    g1_rem_set()->prepare_for_oops_into_collection_set_do();
   6.271    concurrent_g1_refine()->set_use_cache(false);
   6.272    int n_workers = (ParallelGCThreads > 0 ? workers()->total_workers() : 1);
   6.273 -
   6.274    set_par_threads(n_workers);
   6.275    G1ParTask g1_par_task(this, n_workers, _task_queues);
   6.276  
   6.277 @@ -4390,8 +4469,9 @@
   6.278  
   6.279    change_strong_roots_parity();  // In preparation for parallel strong roots.
   6.280    rem_set()->prepare_for_younger_refs_iterate(true);
   6.281 +
   6.282 +  assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
   6.283    double start_par = os::elapsedTime();
   6.284 -
   6.285    if (ParallelGCThreads > 0) {
   6.286      // The individual threads will set their evac-failure closures.
   6.287      workers()->run_task(&g1_par_task);
   6.288 @@ -4411,8 +4491,8 @@
   6.289      G1KeepAliveClosure keep_alive(this);
   6.290      JNIHandles::weak_oops_do(&is_alive, &keep_alive);
   6.291    }
   6.292 -
   6.293    g1_rem_set()->cleanup_after_oops_into_collection_set_do();
   6.294 +
   6.295    concurrent_g1_refine()->set_use_cache(true);
   6.296  
   6.297    finalize_for_evac_failure();
   6.298 @@ -4423,7 +4503,6 @@
   6.299  
   6.300    if (evacuation_failed()) {
   6.301      remove_self_forwarding_pointers();
   6.302 -
   6.303      if (PrintGCDetails) {
   6.304        gclog_or_tty->print(" (evacuation failed)");
   6.305      } else if (PrintGC) {
   6.306 @@ -4431,6 +4510,14 @@
   6.307      }
   6.308    }
   6.309  
   6.310 +  if (G1DeferredRSUpdate) {
   6.311 +    RedirtyLoggedCardTableEntryFastClosure redirty;
   6.312 +    dirty_card_queue_set().set_closure(&redirty);
   6.313 +    dirty_card_queue_set().apply_closure_to_all_completed_buffers();
   6.314 +    JavaThread::dirty_card_queue_set().merge_bufferlists(&dirty_card_queue_set());
   6.315 +    assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
   6.316 +  }
   6.317 +
   6.318    COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
   6.319  }
   6.320  
     7.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu Mar 05 22:07:29 2009 -0500
     7.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Mon Mar 09 11:32:57 2009 -0400
     7.3 @@ -457,6 +457,10 @@
     7.4    // And it's mod ref barrier set, used to track updates for the above.
     7.5    ModRefBarrierSet* _mr_bs;
     7.6  
     7.7 +  // A set of cards that cover the objects for which the Rsets should be updated
     7.8 +  // concurrently after the collection.
     7.9 +  DirtyCardQueueSet _dirty_card_queue_set;
    7.10 +
    7.11    // The Heap Region Rem Set Iterator.
    7.12    HeapRegionRemSetIterator** _rem_set_iterator;
    7.13  
    7.14 @@ -666,6 +670,9 @@
    7.15  
    7.16    RefToScanQueue *task_queue(int i);
    7.17  
    7.18 +  // A set of cards where updates happened during the GC
    7.19 +  DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
    7.20 +
    7.21    // Create a G1CollectedHeap with the specified policy.
    7.22    // Must call the initialize method afterwards.
    7.23    // May not return if something goes wrong.
     8.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Thu Mar 05 22:07:29 2009 -0500
     8.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Mon Mar 09 11:32:57 2009 -0400
     8.3 @@ -177,11 +177,19 @@
     8.4      _cards_scanned(NULL), _total_cards_scanned(0)
     8.5  {
     8.6    _seq_task = new SubTasksDone(NumSeqTasks);
     8.7 -  _new_refs = NEW_C_HEAP_ARRAY(GrowableArray<oop*>*, ParallelGCThreads);
     8.8 +  guarantee(n_workers() > 0, "There should be some workers");
     8.9 +  _new_refs = NEW_C_HEAP_ARRAY(GrowableArray<oop*>*, n_workers());
    8.10 +  for (uint i = 0; i < n_workers(); i++) {
    8.11 +    _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<oop*>(8192,true);
    8.12 +  }
    8.13  }
    8.14  
    8.15  HRInto_G1RemSet::~HRInto_G1RemSet() {
    8.16    delete _seq_task;
    8.17 +  for (uint i = 0; i < n_workers(); i++) {
    8.18 +    delete _new_refs[i];
    8.19 +  }
    8.20 +  FREE_C_HEAP_ARRAY(GrowableArray<oop*>*, _new_refs);
    8.21  }
    8.22  
    8.23  void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) {
    8.24 @@ -281,8 +289,9 @@
    8.25          if (!_ct_bs->is_card_claimed(card_index) &&
    8.26              !_ct_bs->is_card_dirty(card_index)) {
    8.27            assert(_ct_bs->is_card_clean(card_index) ||
    8.28 -                 _ct_bs->is_card_claimed(card_index),
    8.29 -                 "Card is either dirty, clean, or claimed");
    8.30 +                 _ct_bs->is_card_claimed(card_index) ||
    8.31 +                 _ct_bs->is_card_deferred(card_index),
    8.32 +                 "Card is either clean, claimed or deferred");
    8.33            if (_ct_bs->claim_card(card_index))
    8.34              scanCard(card_index, card_region);
    8.35          }
    8.36 @@ -338,14 +347,12 @@
    8.37  
    8.38    _g1p->record_scan_rs_start_time(worker_i, rs_time_start * 1000.0);
    8.39    _g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0);
    8.40 -  if (ParallelGCThreads > 0) {
    8.41 -    // In this case, we called scanNewRefsRS and recorded the corresponding
    8.42 -    // time.
    8.43 -    double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i);
    8.44 -    if (scan_new_refs_time_ms > 0.0) {
    8.45 -      closure_app_time_ms += scan_new_refs_time_ms;
    8.46 -    }
    8.47 +
    8.48 +  double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i);
    8.49 +  if (scan_new_refs_time_ms > 0.0) {
    8.50 +    closure_app_time_ms += scan_new_refs_time_ms;
    8.51    }
    8.52 +
    8.53    _g1p->record_obj_copy_time(worker_i, closure_app_time_ms);
    8.54  }
    8.55  
    8.56 @@ -469,8 +476,8 @@
    8.57    double scan_new_refs_start_sec = os::elapsedTime();
    8.58    G1CollectedHeap* g1h = G1CollectedHeap::heap();
    8.59    CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set());
    8.60 -  while (_new_refs[worker_i]->is_nonempty()) {
    8.61 -    oop* p = _new_refs[worker_i]->pop();
    8.62 +  for (int i = 0; i < _new_refs[worker_i]->length(); i++) {
    8.63 +    oop* p = _new_refs[worker_i]->at(i);
    8.64      oop obj = *p;
    8.65      // *p was in the collection set when p was pushed on "_new_refs", but
    8.66      // another thread may have processed this location from an RS, so it
    8.67 @@ -480,10 +487,6 @@
    8.68        HeapRegion* r = g1h->heap_region_containing(p);
    8.69  
    8.70        DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj));
    8.71 -      assert(ParallelGCThreads > 1
    8.72 -             || to->rem_set()->contains_reference(p),
    8.73 -             "Invariant: pushed after being added."
    8.74 -             "(Not reliable in parallel code.)");
    8.75        oc->set_region(r);
    8.76        // If "p" has already been processed concurrently, this is
    8.77        // idempotent.
    8.78 @@ -538,8 +541,8 @@
    8.79      }
    8.80    } else {
    8.81      assert(worker_i == 0, "invariant");
    8.82 -
    8.83      updateRS(0);
    8.84 +    scanNewRefsRS(oc, 0);
    8.85      scanRS(oc, 0);
    8.86    }
    8.87  }
    8.88 @@ -559,11 +562,7 @@
    8.89    assert(!_par_traversal_in_progress, "Invariant between iterations.");
    8.90    if (ParallelGCThreads > 0) {
    8.91      set_par_traversal(true);
    8.92 -    int n_workers = _g1->workers()->total_workers();
    8.93 -    _seq_task->set_par_threads(n_workers);
    8.94 -    for (uint i = 0; i < ParallelGCThreads; i++)
    8.95 -      _new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<oop*>(8192,true);
    8.96 -
    8.97 +    _seq_task->set_par_threads((int)n_workers());
    8.98      if (cg1r->do_traversal()) {
    8.99        updateRS(0);
   8.100        // Have to do this again after updaters
   8.101 @@ -587,6 +586,53 @@
   8.102    }
   8.103  };
   8.104  
   8.105 +class UpdateRSetOopsIntoCSImmediate : public OopClosure {
   8.106 +  G1CollectedHeap* _g1;
   8.107 +public:
   8.108 +  UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { }
   8.109 +  virtual void do_oop(narrowOop* p) {
   8.110 +    guarantee(false, "NYI");
   8.111 +  }
   8.112 +  virtual void do_oop(oop* p) {
   8.113 +    HeapRegion* to = _g1->heap_region_containing(*p);
   8.114 +    if (to->in_collection_set()) {
   8.115 +      if (to->rem_set()->add_reference(p, 0)) {
   8.116 +        _g1->schedule_popular_region_evac(to);
   8.117 +      }
   8.118 +    }
   8.119 +  }
   8.120 +};
   8.121 +
   8.122 +class UpdateRSetOopsIntoCSDeferred : public OopClosure {
   8.123 +  G1CollectedHeap* _g1;
   8.124 +  CardTableModRefBS* _ct_bs;
   8.125 +  DirtyCardQueue* _dcq;
   8.126 +public:
   8.127 +  UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) :
   8.128 +    _g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { }
   8.129 +  virtual void do_oop(narrowOop* p) {
   8.130 +    guarantee(false, "NYI");
   8.131 +  }
   8.132 +  virtual void do_oop(oop* p) {
   8.133 +    oop obj = *p;
   8.134 +    if (_g1->obj_in_cs(obj)) {
   8.135 +      size_t card_index = _ct_bs->index_for(p);
   8.136 +      if (_ct_bs->mark_card_deferred(card_index)) {
   8.137 +        _dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
   8.138 +      }
   8.139 +    }
   8.140 +  }
   8.141 +};
   8.142 +
   8.143 +void HRInto_G1RemSet::new_refs_iterate(OopClosure* cl) {
   8.144 +  for (size_t i = 0; i < n_workers(); i++) {
   8.145 +    for (int j = 0; j < _new_refs[i]->length(); j++) {
   8.146 +      oop* p = _new_refs[i]->at(j);
   8.147 +      cl->do_oop(p);
   8.148 +    }
   8.149 +  }
   8.150 +}
   8.151 +
   8.152  void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() {
   8.153    guarantee( _cards_scanned != NULL, "invariant" );
   8.154    _total_cards_scanned = 0;
   8.155 @@ -609,11 +655,25 @@
   8.156      if (cg1r->do_traversal()) {
   8.157        cg1r->cg1rThread()->set_do_traversal(false);
   8.158      }
   8.159 -    for (uint i = 0; i < ParallelGCThreads; i++) {
   8.160 -      delete _new_refs[i];
   8.161 -    }
   8.162      set_par_traversal(false);
   8.163    }
   8.164 +
   8.165 +  if (_g1->evacuation_failed()) {
   8.166 +    // Restore remembered sets for the regions pointing into
   8.167 +    // the collection set.
   8.168 +    if (G1DeferredRSUpdate) {
   8.169 +      DirtyCardQueue dcq(&_g1->dirty_card_queue_set());
   8.170 +      UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq);
   8.171 +      new_refs_iterate(&deferred_update);
   8.172 +    } else {
   8.173 +      UpdateRSetOopsIntoCSImmediate immediate_update(_g1);
   8.174 +      new_refs_iterate(&immediate_update);
   8.175 +    }
   8.176 +  }
   8.177 +  for (uint i = 0; i < n_workers(); i++) {
   8.178 +    _new_refs[i]->clear();
   8.179 +  }
   8.180 +
   8.181    assert(!_par_traversal_in_progress, "Invariant between iterations.");
   8.182  }
   8.183  
   8.184 @@ -683,7 +743,8 @@
   8.185    bool doHeapRegion(HeapRegion* r) {
   8.186      if (!r->in_collection_set() &&
   8.187          !r->continuesHumongous() &&
   8.188 -        !r->is_young()) {
   8.189 +        !r->is_young() &&
   8.190 +        !r->is_survivor()) {
   8.191        _update_rs_oop_cl.set_from(r);
   8.192        UpdateRSObjectClosure update_rs_obj_cl(&_update_rs_oop_cl);
   8.193  
   8.194 @@ -820,7 +881,7 @@
   8.195    // before all the cards on the region are dirtied. This is unlikely,
   8.196    // and it doesn't happen often, but it can happen. So, the extra
   8.197    // check below filters out those cards.
   8.198 -  if (r->is_young()) {
   8.199 +  if (r->is_young() || r->is_survivor()) {
   8.200      return;
   8.201    }
   8.202    // While we are processing RSet buffers during the collection, we
     9.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Thu Mar 05 22:07:29 2009 -0500
     9.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Mon Mar 09 11:32:57 2009 -0400
     9.3 @@ -155,6 +155,7 @@
     9.4    bool _par_traversal_in_progress;
     9.5    void set_par_traversal(bool b);
     9.6    GrowableArray<oop*>** _new_refs;
     9.7 +  void new_refs_iterate(OopClosure* cl);
     9.8  
     9.9  public:
    9.10    // This is called to reset dual hash tables after the gc pause
    10.1 --- a/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp	Thu Mar 05 22:07:29 2009 -0500
    10.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp	Mon Mar 09 11:32:57 2009 -0400
    10.3 @@ -31,24 +31,7 @@
    10.4  }
    10.5  
    10.6  inline void HRInto_G1RemSet::write_ref_nv(HeapRegion* from, oop* p) {
    10.7 -  oop obj = *p;
    10.8 -  assert(from != NULL && from->is_in_reserved(p),
    10.9 -         "p is not in a from");
   10.10 -  HeapRegion* to = _g1->heap_region_containing(obj);
   10.11 -  if (from != to && to != NULL) {
   10.12 -    if (!to->popular() && !from->is_survivor()) {
   10.13 -#if G1_REM_SET_LOGGING
   10.14 -      gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS"
   10.15 -                             " for region [" PTR_FORMAT ", " PTR_FORMAT ")",
   10.16 -                             p, obj,
   10.17 -                             to->bottom(), to->end());
   10.18 -#endif
   10.19 -      assert(to->rem_set() != NULL, "Need per-region 'into' remsets.");
   10.20 -      if (to->rem_set()->add_reference(p)) {
   10.21 -        _g1->schedule_popular_region_evac(to);
   10.22 -      }
   10.23 -    }
   10.24 -  }
   10.25 +  par_write_ref(from, p, 0);
   10.26  }
   10.27  
   10.28  inline void HRInto_G1RemSet::write_ref(HeapRegion* from, oop* p) {
   10.29 @@ -82,7 +65,22 @@
   10.30    HeapRegion* to = _g1->heap_region_containing(obj);
   10.31    // The test below could be optimized by applying a bit op to to and from.
   10.32    if (to != NULL && from != NULL && from != to) {
   10.33 -    if (!to->popular() && !from->is_survivor()) {
   10.34 +    bool update_delayed = false;
   10.35 +    // There is a tricky infinite loop if we keep pushing
   10.36 +    // self forwarding pointers onto our _new_refs list.
   10.37 +    // The _par_traversal_in_progress flag is true during the collection pause,
   10.38 +    // false during the evacuation failure handing.
   10.39 +    if (_par_traversal_in_progress &&
   10.40 +        to->in_collection_set() && !self_forwarded(obj)) {
   10.41 +      _new_refs[tid]->push(p);
   10.42 +      // Deferred updates to the Cset are either discarded (in the normal case),
   10.43 +      // or processed (if an evacuation failure occurs) at the end
   10.44 +      // of the collection.
   10.45 +      // See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do().
   10.46 +      update_delayed = true;
   10.47 +    }
   10.48 +
   10.49 +    if (!to->popular() && !update_delayed) {
   10.50  #if G1_REM_SET_LOGGING
   10.51        gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS"
   10.52                               " for region [" PTR_FORMAT ", " PTR_FORMAT ")",
   10.53 @@ -94,11 +92,5 @@
   10.54          _g1->schedule_popular_region_evac(to);
   10.55        }
   10.56      }
   10.57 -    // There is a tricky infinite loop if we keep pushing
   10.58 -    // self forwarding pointers onto our _new_refs list.
   10.59 -    if (_par_traversal_in_progress &&
   10.60 -        to->in_collection_set() && !self_forwarded(obj)) {
   10.61 -      _new_refs[tid]->push(p);
   10.62 -    }
   10.63    }
   10.64  }
    11.1 --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp	Thu Mar 05 22:07:29 2009 -0500
    11.2 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp	Mon Mar 09 11:32:57 2009 -0400
    11.3 @@ -172,6 +172,9 @@
    11.4    develop(bool, G1RSBarrierUseQueue, true,                                  \
    11.5            "If true, use queueing RS barrier")                               \
    11.6                                                                              \
    11.7 +  develop(bool, G1DeferredRSUpdate, true,                                   \
    11.8 +          "If true, use deferred RS updates")                               \
    11.9 +                                                                            \
   11.10    develop(bool, G1RSLogCheckCardTable, false,                               \
   11.11            "If true, verify that no dirty cards remain after RS log "        \
   11.12            "processing.")                                                    \
    12.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp	Thu Mar 05 22:07:29 2009 -0500
    12.2 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp	Mon Mar 09 11:32:57 2009 -0400
    12.3 @@ -91,15 +91,17 @@
    12.4    _n_completed_buffers(0),
    12.5    _process_completed_threshold(0), _process_completed(false),
    12.6    _buf_free_list(NULL), _buf_free_list_sz(0)
    12.7 -{}
    12.8 +{
    12.9 +  _fl_owner = this;
   12.10 +}
   12.11  
   12.12  void** PtrQueueSet::allocate_buffer() {
   12.13    assert(_sz > 0, "Didn't set a buffer size.");
   12.14 -  MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
   12.15 -  if (_buf_free_list != NULL) {
   12.16 -    void** res = _buf_free_list;
   12.17 -    _buf_free_list = (void**)_buf_free_list[0];
   12.18 -    _buf_free_list_sz--;
   12.19 +  MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
   12.20 +  if (_fl_owner->_buf_free_list != NULL) {
   12.21 +    void** res = _fl_owner->_buf_free_list;
   12.22 +    _fl_owner->_buf_free_list = (void**)_fl_owner->_buf_free_list[0];
   12.23 +    _fl_owner->_buf_free_list_sz--;
   12.24      // Just override the next pointer with NULL, just in case we scan this part
   12.25      // of the buffer.
   12.26      res[0] = NULL;
   12.27 @@ -111,10 +113,10 @@
   12.28  
   12.29  void PtrQueueSet::deallocate_buffer(void** buf) {
   12.30    assert(_sz > 0, "Didn't set a buffer size.");
   12.31 -  MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
   12.32 -  buf[0] = (void*)_buf_free_list;
   12.33 -  _buf_free_list = buf;
   12.34 -  _buf_free_list_sz++;
   12.35 +  MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
   12.36 +  buf[0] = (void*)_fl_owner->_buf_free_list;
   12.37 +  _fl_owner->_buf_free_list = buf;
   12.38 +  _fl_owner->_buf_free_list_sz++;
   12.39  }
   12.40  
   12.41  void PtrQueueSet::reduce_free_list() {
   12.42 @@ -207,3 +209,58 @@
   12.43  void PtrQueueSet::set_process_completed_threshold(size_t sz) {
   12.44    _process_completed_threshold = sz;
   12.45  }
   12.46 +
   12.47 +// Merge lists of buffers. Notify waiting threads if the length of the list
   12.48 +// exceeds threshold. The source queue is emptied as a result. The queues
   12.49 +// must share the monitor.
   12.50 +void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
   12.51 +  assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
   12.52 +  MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   12.53 +  if (_completed_buffers_tail == NULL) {
   12.54 +    assert(_completed_buffers_head == NULL, "Well-formedness");
   12.55 +    _completed_buffers_head = src->_completed_buffers_head;
   12.56 +    _completed_buffers_tail = src->_completed_buffers_tail;
   12.57 +  } else {
   12.58 +    assert(_completed_buffers_head != NULL, "Well formedness");
   12.59 +    if (src->_completed_buffers_head != NULL) {
   12.60 +      _completed_buffers_tail->next = src->_completed_buffers_head;
   12.61 +      _completed_buffers_tail = src->_completed_buffers_tail;
   12.62 +    }
   12.63 +  }
   12.64 +  _n_completed_buffers += src->_n_completed_buffers;
   12.65 +
   12.66 +  src->_n_completed_buffers = 0;
   12.67 +  src->_completed_buffers_head = NULL;
   12.68 +  src->_completed_buffers_tail = NULL;
   12.69 +
   12.70 +  assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
   12.71 +         _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
   12.72 +         "Sanity");
   12.73 +
   12.74 +  if (!_process_completed &&
   12.75 +      _n_completed_buffers >= _process_completed_threshold) {
   12.76 +    _process_completed = true;
   12.77 +    if (_notify_when_complete)
   12.78 +      _cbl_mon->notify_all();
   12.79 +  }
   12.80 +}
   12.81 +
   12.82 +// Merge free lists of the two queues. The free list of the source
   12.83 +// queue is emptied as a result. The queues must share the same
   12.84 +// mutex that guards free lists.
   12.85 +void PtrQueueSet::merge_freelists(PtrQueueSet* src) {
   12.86 +  assert(_fl_lock == src->_fl_lock, "Should share the same lock");
   12.87 +  MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
   12.88 +  if (_buf_free_list != NULL) {
   12.89 +    void **p = _buf_free_list;
   12.90 +    while (*p != NULL) {
   12.91 +      p = (void**)*p;
   12.92 +    }
   12.93 +    *p = src->_buf_free_list;
   12.94 +  } else {
   12.95 +    _buf_free_list = src->_buf_free_list;
   12.96 +  }
   12.97 +  _buf_free_list_sz += src->_buf_free_list_sz;
   12.98 +  src->_buf_free_list = NULL;
   12.99 +  src->_buf_free_list_sz = 0;
  12.100 +}
    13.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp	Thu Mar 05 22:07:29 2009 -0500
    13.2 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp	Mon Mar 09 11:32:57 2009 -0400
    13.3 @@ -155,6 +155,9 @@
    13.4    Mutex* _fl_lock;
    13.5    void** _buf_free_list;
    13.6    size_t _buf_free_list_sz;
    13.7 +  // Queue set can share a freelist. The _fl_owner variable
    13.8 +  // specifies the owner. It is set to "this" by default.
    13.9 +  PtrQueueSet* _fl_owner;
   13.10  
   13.11    // The size of all buffers in the set.
   13.12    size_t _sz;
   13.13 @@ -188,10 +191,13 @@
   13.14    // Because of init-order concerns, we can't pass these as constructor
   13.15    // arguments.
   13.16    void initialize(Monitor* cbl_mon, Mutex* fl_lock,
   13.17 -                  int max_completed_queue = 0) {
   13.18 +                  int max_completed_queue = 0,
   13.19 +                  PtrQueueSet *fl_owner = NULL) {
   13.20      _max_completed_queue = max_completed_queue;
   13.21      assert(cbl_mon != NULL && fl_lock != NULL, "Init order issue?");
   13.22 -    _cbl_mon = cbl_mon; _fl_lock = fl_lock;
   13.23 +    _cbl_mon = cbl_mon;
   13.24 +    _fl_lock = fl_lock;
   13.25 +    _fl_owner = (fl_owner != NULL) ? fl_owner : this;
   13.26    }
   13.27  
   13.28    // Return an empty oop array of size _sz (required to be non-zero).
   13.29 @@ -228,4 +234,7 @@
   13.30    void reduce_free_list();
   13.31  
   13.32    size_t completed_buffers_num() { return _n_completed_buffers; }
   13.33 +
   13.34 +  void merge_bufferlists(PtrQueueSet* src);
   13.35 +  void merge_freelists(PtrQueueSet* src);
   13.36  };
    14.1 --- a/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Thu Mar 05 22:07:29 2009 -0500
    14.2 +++ b/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Mon Mar 09 11:32:57 2009 -0400
    14.3 @@ -504,6 +504,7 @@
    14.4    // Make sure that the current and next tables agree.  (Another mechanism
    14.5    // takes care of deleting now-unused tables.)
    14.6    _cur = _next;
    14.7 +  set_expanded(false);
    14.8  }
    14.9  
   14.10  void SparsePRT::expand() {
    15.1 --- a/src/share/vm/gc_implementation/g1/sparsePRT.hpp	Thu Mar 05 22:07:29 2009 -0500
    15.2 +++ b/src/share/vm/gc_implementation/g1/sparsePRT.hpp	Mon Mar 09 11:32:57 2009 -0400
    15.3 @@ -274,7 +274,7 @@
    15.4  
    15.5    // Clean up all tables on the expanded list.  Called single threaded.
    15.6    static void cleanup_all();
    15.7 -  RSHashTable* next() const { return _next; }
    15.8 +  RSHashTable* cur() const { return _cur; }
    15.9  
   15.10  
   15.11    void init_iterator(SparsePRTIter* sprt_iter);
   15.12 @@ -300,7 +300,7 @@
   15.13    {}
   15.14  
   15.15    void init(const SparsePRT* sprt) {
   15.16 -    RSHashTableIter::init(sprt->next());
   15.17 +    RSHashTableIter::init(sprt->cur());
   15.18    }
   15.19    bool has_next(size_t& card_index) {
   15.20      return RSHashTableIter::has_next(card_index);
    16.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Thu Mar 05 22:07:29 2009 -0500
    16.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Mon Mar 09 11:32:57 2009 -0400
    16.3 @@ -125,6 +125,8 @@
    16.4      perm_gen->verify_object_start_array();
    16.5    }
    16.6  
    16.7 +  heap->pre_full_gc_dump();
    16.8 +
    16.9    // Filled in below to track the state of the young gen after the collection.
   16.10    bool eden_empty;
   16.11    bool survivors_empty;
   16.12 @@ -363,6 +365,8 @@
   16.13      Universe::print_heap_after_gc();
   16.14    }
   16.15  
   16.16 +  heap->post_full_gc_dump();
   16.17 +
   16.18  #ifdef TRACESPINNING
   16.19    ParallelTaskTerminator::print_termination_counts();
   16.20  #endif
    17.1 --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Thu Mar 05 22:07:29 2009 -0500
    17.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Mon Mar 09 11:32:57 2009 -0400
    17.3 @@ -1982,6 +1982,8 @@
    17.4      heap->record_gen_tops_before_GC();
    17.5    }
    17.6  
    17.7 +  heap->pre_full_gc_dump();
    17.8 +
    17.9    _print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes;
   17.10  
   17.11    // Make sure data structures are sane, make the heap parsable, and do other
   17.12 @@ -2204,6 +2206,8 @@
   17.13      gc_task_manager()->print_task_time_stamps();
   17.14    }
   17.15  
   17.16 +  heap->post_full_gc_dump();
   17.17 +
   17.18  #ifdef TRACESPINNING
   17.19    ParallelTaskTerminator::print_termination_counts();
   17.20  #endif
    18.1 --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Thu Mar 05 22:07:29 2009 -0500
    18.2 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Mon Mar 09 11:32:57 2009 -0400
    18.3 @@ -121,7 +121,7 @@
    18.4      // make the heap parsable (no need to retire TLABs)
    18.5      ch->ensure_parsability(false);
    18.6    }
    18.7 -  HeapInspection::heap_inspection(_out);
    18.8 +  HeapInspection::heap_inspection(_out, _need_prologue /* need_prologue */);
    18.9  }
   18.10  
   18.11  
    19.1 --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp	Thu Mar 05 22:07:29 2009 -0500
    19.2 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp	Mon Mar 09 11:32:57 2009 -0400
    19.3 @@ -112,13 +112,16 @@
    19.4   private:
    19.5    outputStream* _out;
    19.6    bool _full_gc;
    19.7 +  bool _need_prologue;
    19.8   public:
    19.9 -  VM_GC_HeapInspection(outputStream* out, bool request_full_gc) :
   19.10 +  VM_GC_HeapInspection(outputStream* out, bool request_full_gc,
   19.11 +                       bool need_prologue) :
   19.12      VM_GC_Operation(0 /* total collections,      dummy, ignored */,
   19.13                      0 /* total full collections, dummy, ignored */,
   19.14                      request_full_gc) {
   19.15      _out = out;
   19.16      _full_gc = request_full_gc;
   19.17 +    _need_prologue = need_prologue;
   19.18    }
   19.19  
   19.20    ~VM_GC_HeapInspection() {}
    20.1 --- a/src/share/vm/gc_interface/collectedHeap.cpp	Thu Mar 05 22:07:29 2009 -0500
    20.2 +++ b/src/share/vm/gc_interface/collectedHeap.cpp	Mon Mar 09 11:32:57 2009 -0400
    20.3 @@ -294,3 +294,29 @@
    20.4      ThreadLocalAllocBuffer::resize_all_tlabs();
    20.5    }
    20.6  }
    20.7 +
    20.8 +void CollectedHeap::pre_full_gc_dump() {
    20.9 +  if (HeapDumpBeforeFullGC) {
   20.10 +    TraceTime tt("Heap Dump: ", PrintGCDetails, false, gclog_or_tty);
   20.11 +    // We are doing a "major" collection and a heap dump before
   20.12 +    // major collection has been requested.
   20.13 +    HeapDumper::dump_heap();
   20.14 +  }
   20.15 +  if (PrintClassHistogramBeforeFullGC) {
   20.16 +    TraceTime tt("Class Histogram: ", PrintGCDetails, true, gclog_or_tty);
   20.17 +    VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */);
   20.18 +    inspector.doit();
   20.19 +  }
   20.20 +}
   20.21 +
   20.22 +void CollectedHeap::post_full_gc_dump() {
   20.23 +  if (HeapDumpAfterFullGC) {
   20.24 +    TraceTime tt("Heap Dump", PrintGCDetails, false, gclog_or_tty);
   20.25 +    HeapDumper::dump_heap();
   20.26 +  }
   20.27 +  if (PrintClassHistogramAfterFullGC) {
   20.28 +    TraceTime tt("Class Histogram", PrintGCDetails, true, gclog_or_tty);
   20.29 +    VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */);
   20.30 +    inspector.doit();
   20.31 +  }
   20.32 +}
    21.1 --- a/src/share/vm/gc_interface/collectedHeap.hpp	Thu Mar 05 22:07:29 2009 -0500
    21.2 +++ b/src/share/vm/gc_interface/collectedHeap.hpp	Mon Mar 09 11:32:57 2009 -0400
    21.3 @@ -514,6 +514,10 @@
    21.4    // Perform any cleanup actions necessary before allowing a verification.
    21.5    virtual void prepare_for_verify() = 0;
    21.6  
    21.7 +  // Generate any dumps preceding or following a full gc
    21.8 +  void pre_full_gc_dump();
    21.9 +  void post_full_gc_dump();
   21.10 +
   21.11    virtual void print() const = 0;
   21.12    virtual void print_on(outputStream* st) const = 0;
   21.13  
    22.1 --- a/src/share/vm/includeDB_gc	Thu Mar 05 22:07:29 2009 -0500
    22.2 +++ b/src/share/vm/includeDB_gc	Mon Mar 09 11:32:57 2009 -0400
    22.3 @@ -26,10 +26,12 @@
    22.4  
    22.5  collectedHeap.cpp                       collectedHeap.hpp
    22.6  collectedHeap.cpp                       collectedHeap.inline.hpp
    22.7 +collectedHeap.cpp                       heapDumper.hpp
    22.8  collectedHeap.cpp                       init.hpp
    22.9  collectedHeap.cpp                       oop.inline.hpp
   22.10  collectedHeap.cpp                       systemDictionary.hpp
   22.11  collectedHeap.cpp                       thread_<os_family>.inline.hpp
   22.12 +collectedHeap.cpp                       vmGCOperations.hpp
   22.13  
   22.14  collectedHeap.hpp                       allocation.hpp
   22.15  collectedHeap.hpp                       barrierSet.hpp
    23.1 --- a/src/share/vm/memory/cardTableModRefBS.cpp	Thu Mar 05 22:07:29 2009 -0500
    23.2 +++ b/src/share/vm/memory/cardTableModRefBS.cpp	Mon Mar 09 11:32:57 2009 -0400
    23.3 @@ -356,18 +356,62 @@
    23.4    inline_write_ref_field(field, newVal);
    23.5  }
    23.6  
    23.7 +/*
    23.8 +   Claimed and deferred bits are used together in G1 during the evacuation
    23.9 +   pause. These bits can have the following state transitions:
   23.10 +   1. The claimed bit can be put over any other card state. Except that
   23.11 +      the "dirty -> dirty and claimed" transition is checked for in
   23.12 +      G1 code and is not used.
   23.13 +   2. Deferred bit can be set only if the previous state of the card
   23.14 +      was either clean or claimed. mark_card_deferred() is wait-free.
   23.15 +      We do not care if the operation is be successful because if
   23.16 +      it does not it will only result in duplicate entry in the update
   23.17 +      buffer because of the "cache-miss". So it's not worth spinning.
   23.18 + */
   23.19 +
   23.20  
   23.21  bool CardTableModRefBS::claim_card(size_t card_index) {
   23.22    jbyte val = _byte_map[card_index];
   23.23 -  if (val != claimed_card_val()) {
   23.24 -    jbyte res = Atomic::cmpxchg((jbyte) claimed_card_val(), &_byte_map[card_index], val);
   23.25 -    if (res == val)
   23.26 +  assert(val != dirty_card_val(), "Shouldn't claim a dirty card");
   23.27 +  while (val == clean_card_val() ||
   23.28 +         (val & (clean_card_mask_val() | claimed_card_val())) != claimed_card_val()) {
   23.29 +    jbyte new_val = val;
   23.30 +    if (val == clean_card_val()) {
   23.31 +      new_val = (jbyte)claimed_card_val();
   23.32 +    } else {
   23.33 +      new_val = val | (jbyte)claimed_card_val();
   23.34 +    }
   23.35 +    jbyte res = Atomic::cmpxchg(new_val, &_byte_map[card_index], val);
   23.36 +    if (res == val) {
   23.37        return true;
   23.38 -    else return false;
   23.39 +    }
   23.40 +    val = res;
   23.41    }
   23.42    return false;
   23.43  }
   23.44  
   23.45 +bool CardTableModRefBS::mark_card_deferred(size_t card_index) {
   23.46 +  jbyte val = _byte_map[card_index];
   23.47 +  // It's already processed
   23.48 +  if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) {
   23.49 +    return false;
   23.50 +  }
   23.51 +  // Cached bit can be installed either on a clean card or on a claimed card.
   23.52 +  jbyte new_val = val;
   23.53 +  if (val == clean_card_val()) {
   23.54 +    new_val = (jbyte)deferred_card_val();
   23.55 +  } else {
   23.56 +    if (val & claimed_card_val()) {
   23.57 +      new_val = val | (jbyte)deferred_card_val();
   23.58 +    }
   23.59 +  }
   23.60 +  if (new_val != val) {
   23.61 +    Atomic::cmpxchg(new_val, &_byte_map[card_index], val);
   23.62 +  }
   23.63 +  return true;
   23.64 +}
   23.65 +
   23.66 +
   23.67  void CardTableModRefBS::non_clean_card_iterate(Space* sp,
   23.68                                                 MemRegion mr,
   23.69                                                 DirtyCardToOopClosure* dcto_cl,
    24.1 --- a/src/share/vm/memory/cardTableModRefBS.hpp	Thu Mar 05 22:07:29 2009 -0500
    24.2 +++ b/src/share/vm/memory/cardTableModRefBS.hpp	Mon Mar 09 11:32:57 2009 -0400
    24.3 @@ -52,11 +52,15 @@
    24.4  
    24.5    enum CardValues {
    24.6      clean_card                  = -1,
    24.7 +    // The mask contains zeros in places for all other values.
    24.8 +    clean_card_mask             = clean_card - 31,
    24.9 +
   24.10      dirty_card                  =  0,
   24.11      precleaned_card             =  1,
   24.12 -    claimed_card                =  3,
   24.13 -    last_card                   =  4,
   24.14 -    CT_MR_BS_last_reserved      = 10
   24.15 +    claimed_card                =  2,
   24.16 +    deferred_card               =  4,
   24.17 +    last_card                   =  8,
   24.18 +    CT_MR_BS_last_reserved      = 16
   24.19    };
   24.20  
   24.21    // dirty and precleaned are equivalent wrt younger_refs_iter.
   24.22 @@ -254,9 +258,11 @@
   24.23    };
   24.24  
   24.25    static int clean_card_val()      { return clean_card; }
   24.26 +  static int clean_card_mask_val() { return clean_card_mask; }
   24.27    static int dirty_card_val()      { return dirty_card; }
   24.28    static int claimed_card_val()    { return claimed_card; }
   24.29    static int precleaned_card_val() { return precleaned_card; }
   24.30 +  static int deferred_card_val()   { return deferred_card; }
   24.31  
   24.32    // For RTTI simulation.
   24.33    bool is_a(BarrierSet::Name bsn) {
   24.34 @@ -329,7 +335,8 @@
   24.35    }
   24.36  
   24.37    bool is_card_claimed(size_t card_index) {
   24.38 -    return _byte_map[card_index] == claimed_card_val();
   24.39 +    jbyte val = _byte_map[card_index];
   24.40 +    return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val();
   24.41    }
   24.42  
   24.43    bool claim_card(size_t card_index);
   24.44 @@ -338,6 +345,13 @@
   24.45      return _byte_map[card_index] == clean_card_val();
   24.46    }
   24.47  
   24.48 +  bool is_card_deferred(size_t card_index) {
   24.49 +    jbyte val = _byte_map[card_index];
   24.50 +    return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val();
   24.51 +  }
   24.52 +
   24.53 +  bool mark_card_deferred(size_t card_index);
   24.54 +
   24.55    // Card marking array base (adjusted for heap low boundary)
   24.56    // This would be the 0th element of _byte_map, if the heap started at 0x0.
   24.57    // But since the heap starts at some higher address, this points to somewhere
   24.58 @@ -434,6 +448,10 @@
   24.59      return byte_for(p) - _byte_map;
   24.60    }
   24.61  
   24.62 +  const jbyte* byte_for_index(const size_t card_index) const {
   24.63 +    return _byte_map + card_index;
   24.64 +  }
   24.65 +
   24.66    void verify();
   24.67    void verify_guard();
   24.68  
    25.1 --- a/src/share/vm/memory/genCollectedHeap.cpp	Thu Mar 05 22:07:29 2009 -0500
    25.2 +++ b/src/share/vm/memory/genCollectedHeap.cpp	Mon Mar 09 11:32:57 2009 -0400
    25.3 @@ -456,6 +456,9 @@
    25.4      int max_level_collected = starting_level;
    25.5      for (int i = starting_level; i <= max_level; i++) {
    25.6        if (_gens[i]->should_collect(full, size, is_tlab)) {
    25.7 +        if (i == n_gens() - 1) {  // a major collection is to happen
    25.8 +          pre_full_gc_dump();    // do any pre full gc dumps
    25.9 +        }
   25.10          // Timer for individual generations. Last argument is false: no CR
   25.11          TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty);
   25.12          TraceCollectorStats tcs(_gens[i]->counters());
   25.13 @@ -573,6 +576,10 @@
   25.14      // a whole heap collection.
   25.15      complete = complete || (max_level_collected == n_gens() - 1);
   25.16  
   25.17 +    if (complete) { // We did a "major" collection
   25.18 +      post_full_gc_dump();   // do any post full gc dumps
   25.19 +    }
   25.20 +
   25.21      if (PrintGCDetails) {
   25.22        print_heap_change(gch_prev_used);
   25.23  
    26.1 --- a/src/share/vm/memory/heapInspection.cpp	Thu Mar 05 22:07:29 2009 -0500
    26.2 +++ b/src/share/vm/memory/heapInspection.cpp	Mon Mar 09 11:32:57 2009 -0400
    26.3 @@ -233,7 +233,7 @@
    26.4    size_t missed_count() { return _missed_count; }
    26.5  };
    26.6  
    26.7 -void HeapInspection::heap_inspection(outputStream* st) {
    26.8 +void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) {
    26.9    ResourceMark rm;
   26.10    HeapWord* ref;
   26.11  
   26.12 @@ -244,7 +244,9 @@
   26.13      case CollectedHeap::GenCollectedHeap: {
   26.14        is_shared_heap = true;
   26.15        SharedHeap* sh = (SharedHeap*)heap;
   26.16 -      sh->gc_prologue(false /* !full */); // get any necessary locks, etc.
   26.17 +      if (need_prologue) {
   26.18 +        sh->gc_prologue(false /* !full */); // get any necessary locks, etc.
   26.19 +      }
   26.20        ref = sh->perm_gen()->used_region().start();
   26.21        break;
   26.22      }
   26.23 @@ -290,7 +292,7 @@
   26.24    }
   26.25    st->flush();
   26.26  
   26.27 -  if (is_shared_heap) {
   26.28 +  if (need_prologue && is_shared_heap) {
   26.29      SharedHeap* sh = (SharedHeap*)heap;
   26.30      sh->gc_epilogue(false /* !full */); // release all acquired locks, etc.
   26.31    }
    27.1 --- a/src/share/vm/memory/heapInspection.hpp	Thu Mar 05 22:07:29 2009 -0500
    27.2 +++ b/src/share/vm/memory/heapInspection.hpp	Mon Mar 09 11:32:57 2009 -0400
    27.3 @@ -127,6 +127,6 @@
    27.4  
    27.5  class HeapInspection : public AllStatic {
    27.6   public:
    27.7 -  static void heap_inspection(outputStream* st) KERNEL_RETURN;
    27.8 +  static void heap_inspection(outputStream* st, bool need_prologue) KERNEL_RETURN;
    27.9    static void find_instances_at_safepoint(klassOop k, GrowableArray<oop>* result) KERNEL_RETURN;
   27.10  };
    28.1 --- a/src/share/vm/runtime/globals.hpp	Thu Mar 05 22:07:29 2009 -0500
    28.2 +++ b/src/share/vm/runtime/globals.hpp	Mon Mar 09 11:32:57 2009 -0400
    28.3 @@ -662,6 +662,12 @@
    28.4    product(ccstrlist, OnOutOfMemoryError, "",                                \
    28.5            "Run user-defined commands on first java.lang.OutOfMemoryError")  \
    28.6                                                                              \
    28.7 +  manageable(bool, HeapDumpBeforeFullGC, false,                             \
    28.8 +          "Dump heap to file before any major stop-world GC")               \
    28.9 +                                                                            \
   28.10 +  manageable(bool, HeapDumpAfterFullGC, false,                              \
   28.11 +          "Dump heap to file after any major stop-world GC")                \
   28.12 +                                                                            \
   28.13    manageable(bool, HeapDumpOnOutOfMemoryError, false,                       \
   28.14            "Dump heap to file when java.lang.OutOfMemoryError is thrown")    \
   28.15                                                                              \
   28.16 @@ -1971,6 +1977,12 @@
   28.17    product(bool, PrintHeapAtSIGBREAK, true,                                  \
   28.18            "Print heap layout in response to SIGBREAK")                      \
   28.19                                                                              \
   28.20 +  manageable(bool, PrintClassHistogramBeforeFullGC, false,                  \
   28.21 +          "Print a class histogram before any major stop-world GC")         \
   28.22 +                                                                            \
   28.23 +  manageable(bool, PrintClassHistogramAfterFullGC, false,                   \
   28.24 +          "Print a class histogram after any major stop-world GC")          \
   28.25 +                                                                            \
   28.26    manageable(bool, PrintClassHistogram, false,                              \
   28.27            "Print a histogram of class instances")                           \
   28.28                                                                              \
    29.1 --- a/src/share/vm/runtime/os.cpp	Thu Mar 05 22:07:29 2009 -0500
    29.2 +++ b/src/share/vm/runtime/os.cpp	Mon Mar 09 11:32:57 2009 -0400
    29.3 @@ -207,7 +207,8 @@
    29.4          VMThread::execute(&op1);
    29.5          Universe::print_heap_at_SIGBREAK();
    29.6          if (PrintClassHistogram) {
    29.7 -          VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */);
    29.8 +          VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */,
    29.9 +                                   true /* need_prologue */);
   29.10            VMThread::execute(&op1);
   29.11          }
   29.12          if (JvmtiExport::should_post_data_dump()) {
    30.1 --- a/src/share/vm/services/attachListener.cpp	Thu Mar 05 22:07:29 2009 -0500
    30.2 +++ b/src/share/vm/services/attachListener.cpp	Mon Mar 09 11:32:57 2009 -0400
    30.3 @@ -194,7 +194,7 @@
    30.4      }
    30.5      live_objects_only = strcmp(arg0, "-live") == 0;
    30.6    }
    30.7 -  VM_GC_HeapInspection heapop(out, live_objects_only /* request gc */);
    30.8 +  VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
    30.9    VMThread::execute(&heapop);
   30.10    return JNI_OK;
   30.11  }
    31.1 --- a/src/share/vm/services/heapDumper.cpp	Thu Mar 05 22:07:29 2009 -0500
    31.2 +++ b/src/share/vm/services/heapDumper.cpp	Mon Mar 09 11:32:57 2009 -0400
    31.3 @@ -347,7 +347,6 @@
    31.4    INITIAL_CLASS_COUNT = 200
    31.5  };
    31.6  
    31.7 -
    31.8  // Supports I/O operations on a dump file
    31.9  
   31.10  class DumpWriter : public StackObj {
   31.11 @@ -1303,7 +1302,9 @@
   31.12  // The VM operation that performs the heap dump
   31.13  class VM_HeapDumper : public VM_GC_Operation {
   31.14   private:
   31.15 -  DumpWriter* _writer;
   31.16 +  static VM_HeapDumper* _global_dumper;
   31.17 +  static DumpWriter*    _global_writer;
   31.18 +  DumpWriter*           _local_writer;
   31.19    bool _gc_before_heap_dump;
   31.20    bool _is_segmented_dump;
   31.21    jlong _dump_start;
   31.22 @@ -1311,8 +1312,20 @@
   31.23    ThreadStackTrace** _stack_traces;
   31.24    int _num_threads;
   31.25  
   31.26 -  // accessors
   31.27 -  DumpWriter* writer() const                    { return _writer; }
   31.28 +  // accessors and setters
   31.29 +  static VM_HeapDumper* dumper()         {  assert(_global_dumper != NULL, "Error"); return _global_dumper; }
   31.30 +  static DumpWriter* writer()            {  assert(_global_writer != NULL, "Error"); return _global_writer; }
   31.31 +  void set_global_dumper() {
   31.32 +    assert(_global_dumper == NULL, "Error");
   31.33 +    _global_dumper = this;
   31.34 +  }
   31.35 +  void set_global_writer() {
   31.36 +    assert(_global_writer == NULL, "Error");
   31.37 +    _global_writer = _local_writer;
   31.38 +  }
   31.39 +  void clear_global_dumper() { _global_dumper = NULL; }
   31.40 +  void clear_global_writer() { _global_writer = NULL; }
   31.41 +
   31.42    bool is_segmented_dump() const                { return _is_segmented_dump; }
   31.43    void set_segmented_dump()                     { _is_segmented_dump = true; }
   31.44    jlong dump_start() const                      { return _dump_start; }
   31.45 @@ -1357,7 +1370,7 @@
   31.46      VM_GC_Operation(0 /* total collections,      dummy, ignored */,
   31.47                      0 /* total full collections, dummy, ignored */,
   31.48                      gc_before_heap_dump) {
   31.49 -    _writer = writer;
   31.50 +    _local_writer = writer;
   31.51      _gc_before_heap_dump = gc_before_heap_dump;
   31.52      _is_segmented_dump = false;
   31.53      _dump_start = (jlong)-1;
   31.54 @@ -1381,6 +1394,9 @@
   31.55    void doit();
   31.56  };
   31.57  
   31.58 +VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL;
   31.59 +DumpWriter*    VM_HeapDumper::_global_writer = NULL;
   31.60 +
   31.61  bool VM_HeapDumper::skip_operation() const {
   31.62    return false;
   31.63  }
   31.64 @@ -1479,31 +1495,28 @@
   31.65  void VM_HeapDumper::do_load_class(klassOop k) {
   31.66    static u4 class_serial_num = 0;
   31.67  
   31.68 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
   31.69 -  DumpWriter* writer = dumper->writer();
   31.70 -
   31.71    // len of HPROF_LOAD_CLASS record
   31.72    u4 remaining = 2*oopSize + 2*sizeof(u4);
   31.73  
   31.74    // write a HPROF_LOAD_CLASS for the class and each array class
   31.75    do {
   31.76 -    DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining);
   31.77 +    DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
   31.78  
   31.79      // class serial number is just a number
   31.80 -    writer->write_u4(++class_serial_num);
   31.81 +    writer()->write_u4(++class_serial_num);
   31.82  
   31.83      // class ID
   31.84      Klass* klass = Klass::cast(k);
   31.85 -    writer->write_classID(klass);
   31.86 +    writer()->write_classID(klass);
   31.87  
   31.88      // add the klassOop and class serial number pair
   31.89 -    dumper->add_class_serial_number(klass, class_serial_num);
   31.90 +    dumper()->add_class_serial_number(klass, class_serial_num);
   31.91  
   31.92 -    writer->write_u4(STACK_TRACE_ID);
   31.93 +    writer()->write_u4(STACK_TRACE_ID);
   31.94  
   31.95      // class name ID
   31.96      symbolOop name = klass->name();
   31.97 -    writer->write_objectID(name);
   31.98 +    writer()->write_objectID(name);
   31.99  
  31.100      // write a LOAD_CLASS record for the array type (if it exists)
  31.101      k = klass->array_klass_or_null();
  31.102 @@ -1512,17 +1525,13 @@
  31.103  
  31.104  // writes a HPROF_GC_CLASS_DUMP record for the given class
  31.105  void VM_HeapDumper::do_class_dump(klassOop k) {
  31.106 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
  31.107 -  DumpWriter* writer = dumper->writer();
  31.108 -  DumperSupport::dump_class_and_array_classes(writer, k);
  31.109 +  DumperSupport::dump_class_and_array_classes(writer(), k);
  31.110  }
  31.111  
  31.112  // writes a HPROF_GC_CLASS_DUMP records for a given basic type
  31.113  // array (and each multi-dimensional array too)
  31.114  void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) {
  31.115 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
  31.116 -  DumpWriter* writer = dumper->writer();
  31.117 -  DumperSupport::dump_basic_type_array_class(writer, k);
  31.118 +  DumperSupport::dump_basic_type_array_class(writer(), k);
  31.119  }
  31.120  
  31.121  // Walk the stack of the given thread.
  31.122 @@ -1658,6 +1667,11 @@
  31.123      ch->ensure_parsability(false);
  31.124    }
  31.125  
  31.126 +  // At this point we should be the only dumper active, so
  31.127 +  // the following should be safe.
  31.128 +  set_global_dumper();
  31.129 +  set_global_writer();
  31.130 +
  31.131    // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1
  31.132    size_t used = ch->used();
  31.133    const char* header;
  31.134 @@ -1667,6 +1681,7 @@
  31.135    } else {
  31.136      header = "JAVA PROFILE 1.0.1";
  31.137    }
  31.138 +
  31.139    // header is few bytes long - no chance to overflow int
  31.140    writer()->write_raw((void*)header, (int)strlen(header));
  31.141    writer()->write_u1(0); // terminator
  31.142 @@ -1723,6 +1738,10 @@
  31.143    // fixes up the length of the dump record. In the case of a segmented
  31.144    // heap then the HPROF_HEAP_DUMP_END record is also written.
  31.145    end_of_dump();
  31.146 +
  31.147 +  // Now we clear the global variables, so that a future dumper might run.
  31.148 +  clear_global_dumper();
  31.149 +  clear_global_writer();
  31.150  }
  31.151  
  31.152  void VM_HeapDumper::dump_stack_traces() {
  31.153 @@ -1790,7 +1809,12 @@
  31.154  
  31.155    // generate the dump
  31.156    VM_HeapDumper dumper(&writer, _gc_before_heap_dump);
  31.157 -  VMThread::execute(&dumper);
  31.158 +  if (Thread::current()->is_VM_thread()) {
  31.159 +    assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
  31.160 +    dumper.doit();
  31.161 +  } else {
  31.162 +    VMThread::execute(&dumper);
  31.163 +  }
  31.164  
  31.165    // close dump file and record any error that the writer may have encountered
  31.166    writer.close();
  31.167 @@ -1845,49 +1869,68 @@
  31.168    }
  31.169  }
  31.170  
  31.171 -
  31.172 -// Called by error reporting
  31.173 +// Called by error reporting by a single Java thread outside of a JVM safepoint,
  31.174 +// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various
  31.175 +// callers are strictly serialized and guaranteed not to interfere below. For more
  31.176 +// general use, however, this method will need modification to prevent
  31.177 +// inteference when updating the static variables base_path and dump_file_seq below.
  31.178  void HeapDumper::dump_heap() {
  31.179 -  static char path[JVM_MAXPATHLEN];
  31.180 +  static char base_path[JVM_MAXPATHLEN] = {'\0'};
  31.181 +  static uint dump_file_seq = 0;
  31.182 +  char   my_path[JVM_MAXPATHLEN] = {'\0'};
  31.183  
  31.184    // The dump file defaults to java_pid<pid>.hprof in the current working
  31.185    // directory. HeapDumpPath=<file> can be used to specify an alternative
  31.186    // dump file name or a directory where dump file is created.
  31.187 -  bool use_default_filename = true;
  31.188 -  if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
  31.189 -    path[0] = '\0'; // HeapDumpPath=<file> not specified
  31.190 -  } else {
  31.191 -    assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long");
  31.192 -    strcpy(path, HeapDumpPath);
  31.193 -    // check if the path is a directory (must exist)
  31.194 -    DIR* dir = os::opendir(path);
  31.195 -    if (dir == NULL) {
  31.196 -      use_default_filename = false;
  31.197 +  if (dump_file_seq == 0) { // first time in, we initialize base_path
  31.198 +    bool use_default_filename = true;
  31.199 +    if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
  31.200 +      // HeapDumpPath=<file> not specified
  31.201      } else {
  31.202 -      // HeapDumpPath specified a directory. We append a file separator
  31.203 -      // (if needed).
  31.204 -      os::closedir(dir);
  31.205 -      size_t fs_len = strlen(os::file_separator());
  31.206 -      if (strlen(path) >= fs_len) {
  31.207 -        char* end = path;
  31.208 -        end += (strlen(path) - fs_len);
  31.209 -        if (strcmp(end, os::file_separator()) != 0) {
  31.210 -          assert(strlen(path) + strlen(os::file_separator()) < sizeof(path),
  31.211 -            "HeapDumpPath too long");
  31.212 -          strcat(path, os::file_separator());
  31.213 +      assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long");
  31.214 +      strcpy(base_path, HeapDumpPath);
  31.215 +      // check if the path is a directory (must exist)
  31.216 +      DIR* dir = os::opendir(base_path);
  31.217 +      if (dir == NULL) {
  31.218 +        use_default_filename = false;
  31.219 +      } else {
  31.220 +        // HeapDumpPath specified a directory. We append a file separator
  31.221 +        // (if needed).
  31.222 +        os::closedir(dir);
  31.223 +        size_t fs_len = strlen(os::file_separator());
  31.224 +        if (strlen(base_path) >= fs_len) {
  31.225 +          char* end = base_path;
  31.226 +          end += (strlen(base_path) - fs_len);
  31.227 +          if (strcmp(end, os::file_separator()) != 0) {
  31.228 +            assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path),
  31.229 +              "HeapDumpPath too long");
  31.230 +            strcat(base_path, os::file_separator());
  31.231 +          }
  31.232          }
  31.233        }
  31.234      }
  31.235 +    // If HeapDumpPath wasn't a file name then we append the default name
  31.236 +    if (use_default_filename) {
  31.237 +      char fn[32];
  31.238 +      sprintf(fn, "java_pid%d", os::current_process_id());
  31.239 +      assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long");
  31.240 +      strcat(base_path, fn);
  31.241 +    }
  31.242 +    assert(strlen(base_path) < sizeof(my_path), "Buffer too small");
  31.243 +    strcpy(my_path, base_path);
  31.244 +  } else {
  31.245 +    // Append a sequence number id for dumps following the first
  31.246 +    char fn[33];
  31.247 +    sprintf(fn, ".%d", dump_file_seq);
  31.248 +    assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long");
  31.249 +    strcpy(my_path, base_path);
  31.250 +    strcat(my_path, fn);
  31.251    }
  31.252 -  // If HeapDumpPath wasn't a file name then we append the default name
  31.253 -  if (use_default_filename) {
  31.254 -    char fn[32];
  31.255 -    sprintf(fn, "java_pid%d.hprof", os::current_process_id());
  31.256 -    assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long");
  31.257 -    strcat(path, fn);
  31.258 -  }
  31.259 +  dump_file_seq++;   // increment seq number for next time we dump
  31.260 +  assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long");
  31.261 +  strcat(my_path, ".hprof");
  31.262  
  31.263    HeapDumper dumper(false /* no GC before heap dump */,
  31.264                      true  /* send to tty */);
  31.265 -  dumper.dump(path);
  31.266 +  dumper.dump(my_path);
  31.267  }
    32.1 --- a/src/share/vm/services/heapDumper.hpp	Thu Mar 05 22:07:29 2009 -0500
    32.2 +++ b/src/share/vm/services/heapDumper.hpp	Mon Mar 09 11:32:57 2009 -0400
    32.3 @@ -53,7 +53,7 @@
    32.4  
    32.5   public:
    32.6    HeapDumper(bool gc_before_heap_dump) :
    32.7 -    _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false)  { }
    32.8 +    _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false) { }
    32.9    HeapDumper(bool gc_before_heap_dump, bool print_to_tty) :
   32.10      _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty) { }
   32.11  

mercurial