changeset 7003:2c2fbe2d095a

Merge
author jmasa
date Thu, 28 Aug 2014 11:25:09 -0700
parents 3e66f85c4b33 14c813b8ba20
children fb7e346a0f3f
files
diffstat 20 files changed, 133 insertions(+), 566 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -328,9 +328,11 @@
 void ConcurrentMarkSweepGeneration::initialize_performance_counters() {
 
   const char* gen_name = "old";
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation Counters - generation 1, 1 subspace
-  _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+  _gen_counters = new GenerationCounters(gen_name, 1, 1,
+      gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
 
   _space_counters = new GSpaceCounters(gen_name, 0,
                                        _virtual_space.reserved_size(),
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -434,10 +434,6 @@
   }
 }
 
-bool ConcurrentMark::not_yet_marked(oop obj) const {
-  return _g1h->is_obj_ill(obj);
-}
-
 CMRootRegions::CMRootRegions() :
   _young_list(NULL), _cm(NULL), _scan_in_progress(false),
   _should_abort(false),  _next_survivor(NULL) { }
@@ -1117,20 +1113,17 @@
     if (!_cm->has_aborted()) {
       do {
         double start_vtime_sec = os::elapsedVTime();
-        double start_time_sec = os::elapsedTime();
         double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
 
         the_task->do_marking_step(mark_step_duration_ms,
                                   true  /* do_termination */,
                                   false /* is_serial*/);
 
-        double end_time_sec = os::elapsedTime();
         double end_vtime_sec = os::elapsedVTime();
         double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
-        double elapsed_time_sec = end_time_sec - start_time_sec;
         _cm->clear_has_overflown();
 
-        bool ret = _cm->do_yield_check(worker_id);
+        _cm->do_yield_check(worker_id);
 
         jlong sleep_time_ms;
         if (!_cm->has_aborted() && the_task->has_aborted()) {
@@ -1140,17 +1133,6 @@
           os::sleep(Thread::current(), sleep_time_ms, false);
           SuspendibleThreadSet::join();
         }
-        double end_time2_sec = os::elapsedTime();
-        double elapsed_time2_sec = end_time2_sec - start_time_sec;
-
-#if 0
-          gclog_or_tty->print_cr("CM: elapsed %1.4lf ms, sleep %1.4lf ms, "
-                                 "overhead %1.4lf",
-                                 elapsed_vtime_sec * 1000.0, (double) sleep_time_ms,
-                                 the_task->conc_overhead(os::elapsedTime()) * 8.0);
-          gclog_or_tty->print_cr("elapsed time %1.4lf ms, time 2: %1.4lf ms",
-                                 elapsed_time_sec * 1000.0, elapsed_time2_sec * 1000.0);
-#endif
       } while (!_cm->has_aborted() && the_task->has_aborted());
     }
     the_task->record_end_time();
@@ -2949,11 +2931,6 @@
   _nextMarkBitMap->clearRange(mr);
 }
 
-void ConcurrentMark::clearRangeBothBitmaps(MemRegion mr) {
-  clearRangePrevBitmap(mr);
-  clearRangeNextBitmap(mr);
-}
-
 HeapRegion*
 ConcurrentMark::claim_region(uint worker_id) {
   // "checkpoint" the finger
@@ -3499,17 +3476,6 @@
   }
 }
 
-bool ConcurrentMark::containing_card_is_marked(void* p) {
-  size_t offset = pointer_delta(p, _g1h->reserved_region().start(), 1);
-  return _card_bm.at(offset >> CardTableModRefBS::card_shift);
-}
-
-bool ConcurrentMark::containing_cards_are_marked(void* start,
-                                                 void* last) {
-  return containing_card_is_marked(start) &&
-         containing_card_is_marked(last);
-}
-
 #ifndef PRODUCT
 // for debugging purposes
 void ConcurrentMark::print_finger() {
@@ -3762,7 +3728,7 @@
 
   if (_cm->verbose_medium()) {
       gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, "
-                        "scanned = %d%s, refs reached = %d%s",
+                        "scanned = "SIZE_FORMAT"%s, refs reached = "SIZE_FORMAT"%s",
                         _worker_id, last_interval_ms,
                         _words_scanned,
                         (_words_scanned >= _words_scanned_limit) ? " (*)" : "",
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -683,7 +683,9 @@
     return _task_queues->steal(worker_id, hash_seed, obj);
   }
 
-  ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage);
+  ConcurrentMark(G1CollectedHeap* g1h,
+                 G1RegionToSpaceMapper* prev_bitmap_storage,
+                 G1RegionToSpaceMapper* next_bitmap_storage);
   ~ConcurrentMark();
 
   ConcurrentMarkThread* cmThread() { return _cmThread; }
@@ -712,8 +714,10 @@
   // inconsistent) and always passing the size. hr is the region that
   // contains the object and it's passed optionally from callers who
   // might already have it (no point in recalculating it).
-  inline void grayRoot(oop obj, size_t word_size,
-                       uint worker_id, HeapRegion* hr = NULL);
+  inline void grayRoot(oop obj,
+                       size_t word_size,
+                       uint worker_id,
+                       HeapRegion* hr = NULL);
 
   // It iterates over the heap and for each object it comes across it
   // will dump the contents of its reference fields, as well as
@@ -734,7 +738,8 @@
   //   AND MARKED : indicates that an object is both explicitly and
   //   implicitly live (it should be one or the other, not both)
   void print_reachable(const char* str,
-                       VerifyOption vo, bool all) PRODUCT_RETURN;
+                       VerifyOption vo,
+                       bool all) PRODUCT_RETURN;
 
   // Clear the next marking bitmap (will be called concurrently).
   void clearNextBitmap();
@@ -771,12 +776,11 @@
   // this carefully!
   inline void markPrev(oop p);
 
-  // Clears marks for all objects in the given range, for the prev,
-  // next, or both bitmaps.  NB: the previous bitmap is usually
+  // Clears marks for all objects in the given range, for the prev or
+  // next bitmaps.  NB: the previous bitmap is usually
   // read-only, so use this carefully!
   void clearRangePrevBitmap(MemRegion mr);
   void clearRangeNextBitmap(MemRegion mr);
-  void clearRangeBothBitmaps(MemRegion mr);
 
   // Notify data structures that a GC has started.
   void note_start_of_gc() {
@@ -798,21 +802,6 @@
                            bool verify_thread_buffers,
                            bool verify_fingers) PRODUCT_RETURN;
 
-  bool isMarked(oop p) const {
-    assert(p != NULL && p->is_oop(), "expected an oop");
-    HeapWord* addr = (HeapWord*)p;
-    assert(addr >= _nextMarkBitMap->startWord() ||
-           addr < _nextMarkBitMap->endWord(), "in a region");
-
-    return _nextMarkBitMap->isMarked(addr);
-  }
-
-  inline bool not_yet_marked(oop p) const;
-
-  // XXX Debug code
-  bool containing_card_is_marked(void* p);
-  bool containing_cards_are_marked(void* start, void* last);
-
   bool isPrevMarked(oop p) const {
     assert(p != NULL && p->is_oop(), "expected an oop");
     HeapWord* addr = (HeapWord*)p;
@@ -898,7 +887,8 @@
   // marked_bytes array slot for the given HeapRegion.
   // Sets the bits in the given card bitmap that are associated with the
   // cards that are spanned by the memory region.
-  inline void count_region(MemRegion mr, HeapRegion* hr,
+  inline void count_region(MemRegion mr,
+                           HeapRegion* hr,
                            size_t* marked_bytes_array,
                            BitMap* task_card_bm);
 
@@ -906,56 +896,27 @@
   // data structures for the given worker id.
   inline void count_region(MemRegion mr, HeapRegion* hr, uint worker_id);
 
-  // Counts the given memory region in the task/worker counting
-  // data structures for the given worker id.
-  inline void count_region(MemRegion mr, uint worker_id);
-
   // Counts the given object in the given task/worker counting
   // data structures.
-  inline void count_object(oop obj, HeapRegion* hr,
+  inline void count_object(oop obj,
+                           HeapRegion* hr,
                            size_t* marked_bytes_array,
                            BitMap* task_card_bm);
 
-  // Counts the given object in the task/worker counting data
-  // structures for the given worker id.
-  inline void count_object(oop obj, HeapRegion* hr, uint worker_id);
-
   // Attempts to mark the given object and, if successful, counts
   // the object in the given task/worker counting structures.
-  inline bool par_mark_and_count(oop obj, HeapRegion* hr,
+  inline bool par_mark_and_count(oop obj,
+                                 HeapRegion* hr,
                                  size_t* marked_bytes_array,
                                  BitMap* task_card_bm);
 
   // Attempts to mark the given object and, if successful, counts
   // the object in the task/worker counting structures for the
   // given worker id.
-  inline bool par_mark_and_count(oop obj, size_t word_size,
-                                 HeapRegion* hr, uint worker_id);
-
-  // Attempts to mark the given object and, if successful, counts
-  // the object in the task/worker counting structures for the
-  // given worker id.
-  inline bool par_mark_and_count(oop obj, HeapRegion* hr, uint worker_id);
-
-  // Similar to the above routine but we don't know the heap region that
-  // contains the object to be marked/counted, which this routine looks up.
-  inline bool par_mark_and_count(oop obj, uint worker_id);
-
-  // Similar to the above routine but there are times when we cannot
-  // safely calculate the size of obj due to races and we, therefore,
-  // pass the size in as a parameter. It is the caller's responsibility
-  // to ensure that the size passed in for obj is valid.
-  inline bool par_mark_and_count(oop obj, size_t word_size, uint worker_id);
-
-  // Unconditionally mark the given object, and unconditionally count
-  // the object in the counting structures for worker id 0.
-  // Should *not* be called from parallel code.
-  inline bool mark_and_count(oop obj, HeapRegion* hr);
-
-  // Similar to the above routine but we don't know the heap region that
-  // contains the object to be marked/counted, which this routine looks up.
-  // Should *not* be called from parallel code.
-  inline bool mark_and_count(oop obj);
+  inline bool par_mark_and_count(oop obj,
+                                 size_t word_size,
+                                 HeapRegion* hr,
+                                 uint worker_id);
 
   // Returns true if initialization was successfully completed.
   bool completed_initialization() const {
@@ -1227,9 +1188,12 @@
     _finger = new_finger;
   }
 
-  CMTask(uint worker_id, ConcurrentMark *cm,
-         size_t* marked_bytes, BitMap* card_bm,
-         CMTaskQueue* task_queue, CMTaskQueueSet* task_queues);
+  CMTask(uint worker_id,
+         ConcurrentMark *cm,
+         size_t* marked_bytes,
+         BitMap* card_bm,
+         CMTaskQueue* task_queue,
+         CMTaskQueueSet* task_queues);
 
   // it prints statistics associated with this task
   void print_stats();
--- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -125,14 +125,6 @@
   count_region(mr, hr, marked_bytes_array, task_card_bm);
 }
 
-// Counts the given memory region, which may be a single object, in the
-// task/worker counting data structures for the given worker id.
-inline void ConcurrentMark::count_region(MemRegion mr, uint worker_id) {
-  HeapWord* addr = mr.start();
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  count_region(mr, hr, worker_id);
-}
-
 // Counts the given object in the given task/worker counting data structures.
 inline void ConcurrentMark::count_object(oop obj,
                                          HeapRegion* hr,
@@ -142,17 +134,6 @@
   count_region(mr, hr, marked_bytes_array, task_card_bm);
 }
 
-// Counts the given object in the task/worker counting data
-// structures for the given worker id.
-inline void ConcurrentMark::count_object(oop obj,
-                                         HeapRegion* hr,
-                                         uint worker_id) {
-  size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
-  BitMap* task_card_bm = count_card_bitmap_for(worker_id);
-  HeapWord* addr = (HeapWord*) obj;
-  count_object(obj, hr, marked_bytes_array, task_card_bm);
-}
-
 // Attempts to mark the given object and, if successful, counts
 // the object in the given task/worker counting structures.
 inline bool ConcurrentMark::par_mark_and_count(oop obj,
@@ -184,63 +165,6 @@
   return false;
 }
 
-// Attempts to mark the given object and, if successful, counts
-// the object in the task/worker counting structures for the
-// given worker id.
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
-                                               HeapRegion* hr,
-                                               uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  if (_nextMarkBitMap->parMark(addr)) {
-    // Update the task specific count data for the object.
-    count_object(obj, hr, worker_id);
-    return true;
-  }
-  return false;
-}
-
-// As above - but we don't know the heap region containing the
-// object and so have to supply it.
-inline bool ConcurrentMark::par_mark_and_count(oop obj, uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  return par_mark_and_count(obj, hr, worker_id);
-}
-
-// Similar to the above routine but we already know the size, in words, of
-// the object that we wish to mark/count
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
-                                               size_t word_size,
-                                               uint worker_id) {
-  HeapWord* addr = (HeapWord*)obj;
-  if (_nextMarkBitMap->parMark(addr)) {
-    // Update the task specific count data for the object.
-    MemRegion mr(addr, word_size);
-    count_region(mr, worker_id);
-    return true;
-  }
-  return false;
-}
-
-// Unconditionally mark the given object, and unconditionally count
-// the object in the counting structures for worker id 0.
-// Should *not* be called from parallel code.
-inline bool ConcurrentMark::mark_and_count(oop obj, HeapRegion* hr) {
-  HeapWord* addr = (HeapWord*)obj;
-  _nextMarkBitMap->mark(addr);
-  // Update the task specific count data for the object.
-  count_object(obj, hr, 0 /* worker_id */);
-  return true;
-}
-
-// As above - but we don't have the heap region containing the
-// object, so we have to supply it.
-inline bool ConcurrentMark::mark_and_count(oop obj) {
-  HeapWord* addr = (HeapWord*)obj;
-  HeapRegion* hr = _g1h->heap_region_containing_raw(addr);
-  return mark_and_count(obj, hr);
-}
-
 inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) {
   HeapWord* start_addr = MAX2(startWord(), mr.start());
   HeapWord* end_addr = MIN2(endWord(), mr.end());
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -32,13 +32,6 @@
 
 
 
-void G1BlockOffsetSharedArrayMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
-  // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
-  // retrieve it here since this would cause firing of several asserts. The code
-  // executed after commit of a region already needs to do some re-initialization of
-  // the HeapRegion, so we combine that.
-}
-
 //////////////////////////////////////////////////////////////////////
 // G1BlockOffsetSharedArray
 //////////////////////////////////////////////////////////////////////
@@ -72,26 +65,16 @@
   return (delta & right_n_bits(LogN_words)) == (size_t)NoBits;
 }
 
-void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
-  set_offset_array(index_for(left), index_for(right -1), offset);
-}
-
 //////////////////////////////////////////////////////////////////////
 // G1BlockOffsetArray
 //////////////////////////////////////////////////////////////////////
 
 G1BlockOffsetArray::G1BlockOffsetArray(G1BlockOffsetSharedArray* array,
-                                       MemRegion mr, bool init_to_zero) :
+                                       MemRegion mr) :
   G1BlockOffsetTable(mr.start(), mr.end()),
   _unallocated_block(_bottom),
-  _array(array), _gsp(NULL),
-  _init_to_zero(init_to_zero) {
+  _array(array), _gsp(NULL) {
   assert(_bottom <= _end, "arguments out of order");
-  if (!_init_to_zero) {
-    // initialize cards to point back to mr.start()
-    set_remainder_to_point_to_start(mr.start() + N_words, mr.end());
-    _array->set_offset_array(0, 0);  // set first card to 0
-  }
 }
 
 void G1BlockOffsetArray::set_space(G1OffsetTableContigSpace* sp) {
@@ -181,93 +164,6 @@
   DEBUG_ONLY(check_all_cards(start_card, end_card);)
 }
 
-// The block [blk_start, blk_end) has been allocated;
-// adjust the block offset table to represent this information;
-// right-open interval: [blk_start, blk_end)
-void
-G1BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
-  mark_block(blk_start, blk_end);
-  allocated(blk_start, blk_end);
-}
-
-// Adjust BOT to show that a previously whole block has been split
-// into two.
-void G1BlockOffsetArray::split_block(HeapWord* blk, size_t blk_size,
-                                     size_t left_blk_size) {
-  // Verify that the BOT shows [blk, blk + blk_size) to be one block.
-  verify_single_block(blk, blk_size);
-  // Update the BOT to indicate that [blk + left_blk_size, blk + blk_size)
-  // is one single block.
-  mark_block(blk + left_blk_size, blk + blk_size);
-}
-
-
-// Action_mark - update the BOT for the block [blk_start, blk_end).
-//               Current typical use is for splitting a block.
-// Action_single - update the BOT for an allocation.
-// Action_verify - BOT verification.
-void G1BlockOffsetArray::do_block_internal(HeapWord* blk_start,
-                                           HeapWord* blk_end,
-                                           Action action) {
-  assert(Universe::heap()->is_in_reserved(blk_start),
-         "reference must be into the heap");
-  assert(Universe::heap()->is_in_reserved(blk_end-1),
-         "limit must be within the heap");
-  // This is optimized to make the test fast, assuming we only rarely
-  // cross boundaries.
-  uintptr_t end_ui = (uintptr_t)(blk_end - 1);
-  uintptr_t start_ui = (uintptr_t)blk_start;
-  // Calculate the last card boundary preceding end of blk
-  intptr_t boundary_before_end = (intptr_t)end_ui;
-  clear_bits(boundary_before_end, right_n_bits(LogN));
-  if (start_ui <= (uintptr_t)boundary_before_end) {
-    // blk starts at or crosses a boundary
-    // Calculate index of card on which blk begins
-    size_t    start_index = _array->index_for(blk_start);
-    // Index of card on which blk ends
-    size_t    end_index   = _array->index_for(blk_end - 1);
-    // Start address of card on which blk begins
-    HeapWord* boundary    = _array->address_for_index(start_index);
-    assert(boundary <= blk_start, "blk should start at or after boundary");
-    if (blk_start != boundary) {
-      // blk starts strictly after boundary
-      // adjust card boundary and start_index forward to next card
-      boundary += N_words;
-      start_index++;
-    }
-    assert(start_index <= end_index, "monotonicity of index_for()");
-    assert(boundary <= (HeapWord*)boundary_before_end, "tautology");
-    switch (action) {
-      case Action_mark: {
-        if (init_to_zero()) {
-          _array->set_offset_array(start_index, boundary, blk_start);
-          break;
-        } // Else fall through to the next case
-      }
-      case Action_single: {
-        _array->set_offset_array(start_index, boundary, blk_start);
-        // We have finished marking the "offset card". We need to now
-        // mark the subsequent cards that this blk spans.
-        if (start_index < end_index) {
-          HeapWord* rem_st = _array->address_for_index(start_index) + N_words;
-          HeapWord* rem_end = _array->address_for_index(end_index) + N_words;
-          set_remainder_to_point_to_start(rem_st, rem_end);
-        }
-        break;
-      }
-      case Action_check: {
-        _array->check_offset_array(start_index, boundary, blk_start);
-        // We have finished checking the "offset card". We need to now
-        // check the subsequent cards that this blk spans.
-        check_all_cards(start_index + 1, end_index);
-        break;
-      }
-      default:
-        ShouldNotReachHere();
-    }
-  }
-}
-
 // The card-interval [start_card, end_card] is a closed interval; this
 // is an expensive check -- use with care and only under protection of
 // suitable flag.
@@ -306,25 +202,6 @@
   }
 }
 
-// The range [blk_start, blk_end) represents a single contiguous block
-// of storage; modify the block offset table to represent this
-// information; Right-open interval: [blk_start, blk_end)
-// NOTE: this method does _not_ adjust _unallocated_block.
-void
-G1BlockOffsetArray::single_block(HeapWord* blk_start, HeapWord* blk_end) {
-  do_block_internal(blk_start, blk_end, Action_single);
-}
-
-// Mark the BOT such that if [blk_start, blk_end) straddles a card
-// boundary, the card following the first such boundary is marked
-// with the appropriate offset.
-// NOTE: this method does _not_ adjust _unallocated_block or
-// any cards subsequent to the first one.
-void
-G1BlockOffsetArray::mark_block(HeapWord* blk_start, HeapWord* blk_end) {
-  do_block_internal(blk_start, blk_end, Action_mark);
-}
-
 HeapWord* G1BlockOffsetArray::block_start_unsafe(const void* addr) {
   assert(_bottom <= addr && addr < _end,
          "addr must be covered by this Array");
@@ -397,57 +274,13 @@
   return forward_to_block_containing_addr_const(q, n, addr);
 }
 
-HeapWord* G1BlockOffsetArray::block_start_careful(const void* addr) const {
-  assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
-
-  assert(_bottom <= addr && addr < _end,
-         "addr must be covered by this Array");
-  // Must read this exactly once because it can be modified by parallel
-  // allocation.
-  HeapWord* ub = _unallocated_block;
-  if (BlockOffsetArrayUseUnallocatedBlock && addr >= ub) {
-    assert(ub < _end, "tautology (see above)");
-    return ub;
-  }
-
-  // Otherwise, find the block start using the table, but taking
-  // care (cf block_start_unsafe() above) not to parse any objects/blocks
-  // on the cards themselves.
-  size_t index = _array->index_for(addr);
-  assert(_array->address_for_index(index) == addr,
-         "arg should be start of card");
-
-  HeapWord* q = (HeapWord*)addr;
-  uint offset;
-  do {
-    offset = _array->offset_array(index--);
-    q -= offset;
-  } while (offset == N_words);
-  assert(q <= addr, "block start should be to left of arg");
-  return q;
-}
-
 // Note that the committed size of the covered space may have changed,
 // so the table size might also wish to change.
 void G1BlockOffsetArray::resize(size_t new_word_size) {
   HeapWord* new_end = _bottom + new_word_size;
-  if (_end < new_end && !init_to_zero()) {
-    // verify that the old and new boundaries are also card boundaries
-    assert(_array->is_card_boundary(_end),
-           "_end not a card boundary");
-    assert(_array->is_card_boundary(new_end),
-           "new _end would not be a card boundary");
-    // set all the newly added cards
-    _array->set_offset_array(_end, new_end, N_words);
-  }
   _end = new_end;  // update _end
 }
 
-void G1BlockOffsetArray::set_region(MemRegion mr) {
-  _bottom = mr.start();
-  _end = mr.end();
-}
-
 //
 //              threshold_
 //              |   _index_
@@ -606,7 +439,7 @@
 G1BlockOffsetArrayContigSpace::
 G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array,
                               MemRegion mr) :
-  G1BlockOffsetArray(array, mr, true)
+  G1BlockOffsetArray(array, mr)
 {
   _next_offset_threshold = NULL;
   _next_offset_index = 0;
@@ -641,15 +474,6 @@
   return _next_offset_threshold;
 }
 
-void G1BlockOffsetArrayContigSpace::zero_bottom_entry() {
-  assert(!Universe::heap()->is_in_reserved(_array->_offset_array),
-         "just checking");
-  size_t bottom_index = _array->index_for(_bottom);
-  assert(_array->address_for_index(bottom_index) == _bottom,
-         "Precondition of call");
-  _array->set_offset_array(bottom_index, 0);
-}
-
 void
 G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) {
   assert(new_top <= _end, "_end should have already been updated");
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -109,7 +109,12 @@
 
 class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener {
  public:
-  virtual void on_commit(uint start_idx, size_t num_regions);
+  virtual void on_commit(uint start_idx, size_t num_regions) {
+    // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot
+    // retrieve it here since this would cause firing of several asserts. The code
+    // executed after commit of a region already needs to do some re-initialization of
+    // the HeapRegion, so we combine that.
+  }
 };
 
 // This implementation of "G1BlockOffsetTable" divides the covered region
@@ -153,8 +158,6 @@
   // For performance these have to devolve to array accesses in product builds.
   inline u_char offset_array(size_t index) const;
 
-  void set_offset_array(HeapWord* left, HeapWord* right, u_char offset);
-
   void set_offset_array_raw(size_t index, u_char offset) {
     _offset_array[index] = offset;
   }
@@ -165,8 +168,6 @@
 
   inline void set_offset_array(size_t left, size_t right, u_char offset);
 
-  inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const;
-
   bool is_card_boundary(HeapWord* p) const;
 
 public:
@@ -193,8 +194,6 @@
   // G1BlockOffsetTable(s) to initialize cards.
   G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage);
 
-  void set_bottom(HeapWord* new_bottom);
-
   // Return the appropriate index into "_offset_array" for "p".
   inline size_t index_for(const void* p) const;
   inline size_t index_for_raw(const void* p) const;
@@ -220,14 +219,6 @@
     LogN    = G1BlockOffsetSharedArray::LogN
   };
 
-  // The following enums are used by do_block_helper
-  enum Action {
-    Action_single,      // BOT records a single block (see single_block())
-    Action_mark,        // BOT marks the start of a block (see mark_block())
-    Action_check        // Check that BOT records block correctly
-                        // (see verify_single_block()).
-  };
-
   // This is the array, which can be shared by several BlockOffsetArray's
   // servicing different
   G1BlockOffsetSharedArray* _array;
@@ -235,10 +226,6 @@
   // The space that owns this subregion.
   G1OffsetTableContigSpace* _gsp;
 
-  // If true, array entries are initialized to 0; otherwise, they are
-  // initialized to point backwards to the beginning of the covered region.
-  bool _init_to_zero;
-
   // The portion [_unallocated_block, _sp.end()) of the space that
   // is a single block known not to contain any objects.
   // NOTE: See BlockOffsetArrayUseUnallocatedBlock flag.
@@ -253,9 +240,6 @@
   // that is closed: [start_index, end_index]
   void set_remainder_to_point_to_start_incl(size_t start, size_t end);
 
-  // A helper function for BOT adjustment/verification work
-  void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action);
-
 protected:
 
   G1OffsetTableContigSpace* gsp() const { return _gsp; }
@@ -303,11 +287,9 @@
 
 public:
   // The space may not have it's bottom and top set yet, which is why the
-  // region is passed as a parameter.  If "init_to_zero" is true, the
-  // elements of the array are initialized to zero.  Otherwise, they are
-  // initialized to point backwards to the beginning.
-  G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr,
-                     bool init_to_zero);
+  // region is passed as a parameter. The elements of the array are
+  // initialized to zero.
+  G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr);
 
   // Note: this ought to be part of the constructor, but that would require
   // "this" to be passed as a parameter to a member constructor for
@@ -315,114 +297,19 @@
   // This would be legal C++, but MS VC++ doesn't allow it.
   void set_space(G1OffsetTableContigSpace* sp);
 
-  // Resets the covered region to the given "mr".
-  void set_region(MemRegion mr);
-
   // Resets the covered region to one with the same _bottom as before but
   // the "new_word_size".
   void resize(size_t new_word_size);
 
-  // These must be guaranteed to work properly (i.e., do nothing)
-  // when "blk_start" ("blk" for second version) is "NULL".
-  virtual void alloc_block(HeapWord* blk_start, HeapWord* blk_end);
-  virtual void alloc_block(HeapWord* blk, size_t size) {
-    alloc_block(blk, blk + size);
-  }
-
-  // The following methods are useful and optimized for a
-  // general, non-contiguous space.
-
-  // Given a block [blk_start, blk_start + full_blk_size), and
-  // a left_blk_size < full_blk_size, adjust the BOT to show two
-  // blocks [blk_start, blk_start + left_blk_size) and
-  // [blk_start + left_blk_size, blk_start + full_blk_size).
-  // It is assumed (and verified in the non-product VM) that the
-  // BOT was correct for the original block.
-  void split_block(HeapWord* blk_start, size_t full_blk_size,
-                           size_t left_blk_size);
-
-  // Adjust the BOT to show that it has a single block in the
-  // range [blk_start, blk_start + size). All necessary BOT
-  // cards are adjusted, but _unallocated_block isn't.
-  void single_block(HeapWord* blk_start, HeapWord* blk_end);
-  void single_block(HeapWord* blk, size_t size) {
-    single_block(blk, blk + size);
-  }
-
-  // Adjust BOT to show that it has a block in the range
-  // [blk_start, blk_start + size). Only the first card
-  // of BOT is touched. It is assumed (and verified in the
-  // non-product VM) that the remaining cards of the block
-  // are correct.
-  void mark_block(HeapWord* blk_start, HeapWord* blk_end);
-  void mark_block(HeapWord* blk, size_t size) {
-    mark_block(blk, blk + size);
-  }
-
-  // Adjust _unallocated_block to indicate that a particular
-  // block has been newly allocated or freed. It is assumed (and
-  // verified in the non-product VM) that the BOT is correct for
-  // the given block.
-  inline void allocated(HeapWord* blk_start, HeapWord* blk_end) {
-    // Verify that the BOT shows [blk, blk + blk_size) to be one block.
-    verify_single_block(blk_start, blk_end);
-    if (BlockOffsetArrayUseUnallocatedBlock) {
-      _unallocated_block = MAX2(_unallocated_block, blk_end);
-    }
-  }
-
-  inline void allocated(HeapWord* blk, size_t size) {
-    allocated(blk, blk + size);
-  }
-
-  inline void freed(HeapWord* blk_start, HeapWord* blk_end);
-
-  inline void freed(HeapWord* blk, size_t size);
-
   virtual HeapWord* block_start_unsafe(const void* addr);
   virtual HeapWord* block_start_unsafe_const(const void* addr) const;
 
-  // Requires "addr" to be the start of a card and returns the
-  // start of the block that contains the given address.
-  HeapWord* block_start_careful(const void* addr) const;
-
-  // If true, initialize array slots with no allocated blocks to zero.
-  // Otherwise, make them point back to the front.
-  bool init_to_zero() { return _init_to_zero; }
-
-  // Verification & debugging - ensure that the offset table reflects the fact
-  // that the block [blk_start, blk_end) or [blk, blk + size) is a
-  // single block of storage. NOTE: can;t const this because of
-  // call to non-const do_block_internal() below.
-  inline void verify_single_block(HeapWord* blk_start, HeapWord* blk_end) {
-    if (VerifyBlockOffsetArray) {
-      do_block_internal(blk_start, blk_end, Action_check);
-    }
-  }
-
-  inline void verify_single_block(HeapWord* blk, size_t size) {
-    verify_single_block(blk, blk + size);
-  }
-
   // Used by region verification. Checks that the contents of the
   // BOT reflect that there's a single object that spans the address
   // range [obj_start, obj_start + word_size); returns true if this is
   // the case, returns false if it's not.
   bool verify_for_object(HeapWord* obj_start, size_t word_size) const;
 
-  // Verify that the given block is before _unallocated_block
-  inline void verify_not_unallocated(HeapWord* blk_start,
-                                     HeapWord* blk_end) const {
-    if (BlockOffsetArrayUseUnallocatedBlock) {
-      assert(blk_start < blk_end, "Block inconsistency?");
-      assert(blk_end <= _unallocated_block, "_unallocated_block problem");
-    }
-  }
-
-  inline void verify_not_unallocated(HeapWord* blk, size_t size) const {
-    verify_not_unallocated(blk, blk + size);
-  }
-
   void check_all_cards(size_t left_card, size_t right_card) const;
 
   virtual void print_on(outputStream* out) PRODUCT_RETURN;
@@ -445,14 +332,12 @@
                       blk_start, blk_end);
   }
 
-  // Variant of zero_bottom_entry that does not check for availability of the
+  // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the
   // memory first.
   void zero_bottom_entry_raw();
   // Variant of initialize_threshold that does not check for availability of the
   // memory first.
   HeapWord* initialize_threshold_raw();
-  // Zero out the entry for _bottom (offset will be zero).
-  void zero_bottom_entry();
  public:
   G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr);
 
--- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -91,13 +91,6 @@
   }
 }
 
-void G1BlockOffsetSharedArray::check_offset_array(size_t index, HeapWord* high, HeapWord* low) const {
-  check_index(index, "index out of range");
-  assert(high >= low, "addresses out of order");
-  check_offset(pointer_delta(high, low), "offset too large");
-  assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset");
-}
-
 // Variant of index_for that does not check the index for validity.
 inline size_t G1BlockOffsetSharedArray::index_for_raw(const void* p) const {
   return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> LogN;
@@ -193,28 +186,4 @@
   return q;
 }
 
-//////////////////////////////////////////////////////////////////////////
-// BlockOffsetArrayNonContigSpace inlines
-//////////////////////////////////////////////////////////////////////////
-inline void G1BlockOffsetArray::freed(HeapWord* blk_start, HeapWord* blk_end) {
-  // Verify that the BOT shows [blk_start, blk_end) to be one block.
-  verify_single_block(blk_start, blk_end);
-  // adjust _unallocated_block upward or downward
-  // as appropriate
-  if (BlockOffsetArrayUseUnallocatedBlock) {
-    assert(_unallocated_block <= _end,
-           "Inconsistent value for _unallocated_block");
-    if (blk_end >= _unallocated_block && blk_start <= _unallocated_block) {
-      // CMS-specific note: a block abutting _unallocated_block to
-      // its left is being freed, a new block is being added or
-      // we are resetting following a compaction
-      _unallocated_block = blk_start;
-    }
-  }
-}
-
-inline void G1BlockOffsetArray::freed(HeapWord* blk, size_t size) {
-  freed(blk, blk + size);
-}
-
 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_INLINE_HPP
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -322,29 +322,6 @@
   return false;
 }
 
-HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) {
-  HeapWord* low = addr;
-  HeapWord* high = end();
-  while (low < high) {
-    size_t diff = pointer_delta(high, low);
-    // Must add one below to bias toward the high amount.  Otherwise, if
-  // "high" were at the desired value, and "low" were one less, we
-    // would not converge on "high".  This is not symmetric, because
-    // we set "high" to a block start, which might be the right one,
-    // which we don't do for "low".
-    HeapWord* middle = low + (diff+1)/2;
-    if (middle == high) return high;
-    HeapWord* mid_bs = block_start_careful(middle);
-    if (mid_bs < addr) {
-      low = middle;
-    } else {
-      high = mid_bs;
-    }
-  }
-  assert(low == high && low >= addr, "Didn't work.");
-  return low;
-}
-
 HeapRegion::HeapRegion(uint hrm_index,
                        G1BlockOffsetSharedArray* sharedOffsetArray,
                        MemRegion mr) :
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -206,10 +206,6 @@
     _offsets.reset_bot();
   }
 
-  void update_bot_for_object(HeapWord* start, size_t word_size) {
-    _offsets.alloc_block(start, word_size);
-  }
-
   void print_bot_on(outputStream* out) {
     _offsets.print_on(out);
   }
@@ -737,18 +733,6 @@
                                    bool filter_young,
                                    jbyte* card_ptr);
 
-  // A version of block start that is guaranteed to find *some* block
-  // boundary at or before "p", but does not object iteration, and may
-  // therefore be used safely when the heap is unparseable.
-  HeapWord* block_start_careful(const void* p) const {
-    return _offsets.block_start_careful(p);
-  }
-
-  // Requires that "addr" is within the region.  Returns the start of the
-  // first ("careful") block that starts at or after "addr", or else the
-  // "end" of the region if there is no such block.
-  HeapWord* next_block_start_careful(HeapWord* addr);
-
   size_t recorded_rs_length() const        { return _recorded_rs_length; }
   double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }
   size_t predicted_bytes_to_copy() const   { return _predicted_bytes_to_copy; }
--- a/src/share/vm/gc_implementation/g1/heapRegionManager.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/g1/heapRegionManager.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -351,10 +351,6 @@
 
   while ((removed < num_regions_to_remove) &&
       (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) {
-    // Only allow uncommit from the end of the heap.
-    if ((idx_last_found + num_last_found) != _allocated_heapregions_length) {
-      return 0;
-    }
     uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found);
 
     uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
--- a/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -30,6 +30,8 @@
 
 PSGenerationCounters::PSGenerationCounters(const char* name,
                                        int ordinal, int spaces,
+                                       size_t min_capacity,
+                                       size_t max_capacity,
                                        PSVirtualSpace* v):
     _ps_virtual_space(v) {
 
@@ -52,11 +54,11 @@
 
     cname = PerfDataManager::counter_name(_name_space, "minCapacity");
     PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
-      _ps_virtual_space->committed_size(), CHECK);
+      min_capacity, CHECK);
 
     cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
     PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
-      _ps_virtual_space->reserved_size(), CHECK);
+      max_capacity, CHECK);
 
     cname = PerfDataManager::counter_name(_name_space, "capacity");
     _current_size = PerfDataManager::create_variable(SUN_GC, cname,
--- a/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/parallelScavenge/psGenerationCounters.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -41,7 +41,7 @@
 
  public:
   PSGenerationCounters(const char* name, int ordinal, int spaces,
-                     PSVirtualSpace* v);
+                       size_t min_capacity, size_t max_capacity, PSVirtualSpace* v);
 
   void update_all() {
     assert(_virtual_space == NULL, "Only one should be in use");
--- a/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -149,8 +149,8 @@
 
 void PSOldGen::initialize_performance_counters(const char* perf_data_name, int level) {
   // Generation Counters, generation 'level', 1 subspace
-  _gen_counters = new PSGenerationCounters(perf_data_name, level, 1,
-                                           virtual_space());
+  _gen_counters = new PSGenerationCounters(perf_data_name, level, 1, _min_gen_size,
+                                           _max_gen_size, virtual_space());
   _space_counters = new SpaceCounters(perf_data_name, 0,
                                       virtual_space()->reserved_size(),
                                       _object_space, _gen_counters);
--- a/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -101,7 +101,8 @@
   }
 
   // Generation Counters - generation 0, 3 subspaces
-  _gen_counters = new PSGenerationCounters("new", 0, 3, _virtual_space);
+  _gen_counters = new PSGenerationCounters("new", 0, 3, _min_gen_size,
+                                           _max_gen_size, _virtual_space);
 
   // Compute maximum space sizes for performance counters
   ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
--- a/src/share/vm/gc_implementation/shared/generationCounters.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/shared/generationCounters.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -62,11 +62,12 @@
 
 GenerationCounters::GenerationCounters(const char* name,
                                        int ordinal, int spaces,
+                                       size_t min_capacity, size_t max_capacity,
                                        VirtualSpace* v)
   : _virtual_space(v) {
   assert(v != NULL, "don't call this constructor if v == NULL");
   initialize(name, ordinal, spaces,
-             v->committed_size(), v->reserved_size(), v->committed_size());
+             min_capacity, max_capacity, v->committed_size());
 }
 
 GenerationCounters::GenerationCounters(const char* name,
--- a/src/share/vm/gc_implementation/shared/generationCounters.hpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/gc_implementation/shared/generationCounters.hpp	Thu Aug 28 11:25:09 2014 -0700
@@ -66,7 +66,7 @@
 
  public:
   GenerationCounters(const char* name, int ordinal, int spaces,
-                     VirtualSpace* v);
+                     size_t min_capacity, size_t max_capacity, VirtualSpace* v);
 
   ~GenerationCounters() {
     if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space, mtGC);
--- a/src/share/vm/memory/defNewGeneration.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/memory/defNewGeneration.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -214,9 +214,11 @@
   _max_eden_size = size - (2*_max_survivor_size);
 
   // allocate the performance counters
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation counters -- generation 0, 3 subspaces
-  _gen_counters = new GenerationCounters("new", 0, 3, &_virtual_space);
+  _gen_counters = new GenerationCounters("new", 0, 3,
+      gcp->min_young_size(), gcp->max_young_size(), &_virtual_space);
   _gc_counters = new CollectorCounters(policy, 0);
 
   _eden_counters = new CSpaceCounters("eden", 0, _max_eden_size, _eden_space,
--- a/src/share/vm/memory/tenuredGeneration.cpp	Thu Aug 28 17:45:58 2014 +0000
+++ b/src/share/vm/memory/tenuredGeneration.cpp	Thu Aug 28 11:25:09 2014 -0700
@@ -53,9 +53,11 @@
   // initialize performance counters
 
   const char* gen_name = "old";
+  GenCollectorPolicy* gcp = (GenCollectorPolicy*) GenCollectedHeap::heap()->collector_policy();
 
   // Generation Counters -- generation 1, 1 subspace
-  _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
+  _gen_counters = new GenerationCounters(gen_name, 1, 1,
+      gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
 
   _gc_counters = new CollectorCounters("MSC", 1);
 
--- a/test/gc/g1/TestHumongousShrinkHeap.java	Thu Aug 28 17:45:58 2014 +0000
+++ b/test/gc/g1/TestHumongousShrinkHeap.java	Thu Aug 28 11:25:09 2014 -0700
@@ -22,9 +22,8 @@
  */
 
 /**
- * @ignore 8041506, 8041946, 8042051
  * @test TestHumongousShrinkHeap
- * @bug 8036025
+ * @bug 8036025 8056043
  * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
  * @library /testlibrary
  * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/whitebox/TestWBGC.java	Thu Aug 28 11:25:09 2014 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestWBGC
+ * @bug 8055098
+ * @summary Test verify that WB methods isObjectInOldGen and youngGC works correctly.
+ * @library /testlibrary /testlibrary/whitebox
+ * @build TestWBGC
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run driver TestWBGC
+ */
+import com.oracle.java.testlibrary.*;
+import sun.hotspot.WhiteBox;
+
+public class TestWBGC {
+
+    public static void main(String args[]) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                true,
+                "-Xbootclasspath/a:.",
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:+WhiteBoxAPI",
+                "-XX:MaxTenuringThreshold=1",
+                "-XX:+PrintGC",
+                GCYoungTest.class.getName());
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        System.out.println(output.getStdout());
+        output.shouldHaveExitValue(0);
+        output.shouldContain("WhiteBox Initiated Young GC");
+        output.shouldNotContain("Full");
+        // To be sure that we don't provoke Full GC additionaly to young
+    }
+
+    public static class GCYoungTest {
+        static WhiteBox wb = WhiteBox.getWhiteBox();
+        public static Object obj;
+
+        public static void main(String args[]) {
+            obj = new Object();
+            Asserts.assertFalse(wb.isObjectInOldGen(obj));
+            wb.youngGC();
+            wb.youngGC();
+            // 2 young GC is needed to promote object into OldGen
+            Asserts.assertTrue(wb.isObjectInOldGen(obj));
+        }
+    }
+}