changeset 10913:f523b7ad0685

Merge
author jwilhelm
date Fri, 15 Apr 2016 17:17:58 +0200
parents d7e875ba78cb 13a7f3426b89
children 9f4012fe09ab 7a311723df33 2f76f418c0dc
files test/stress/gc/TestGCOld.java test/stress/gc/TestMultiThreadStressRSet.java test/stress/gc/TestStressIHOPMultiThread.java test/stress/gc/TestStressRSetCoarsening.java
diffstat 31 files changed, 1591 insertions(+), 1554 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/moduleEntry.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/classfile/moduleEntry.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -36,6 +36,7 @@
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "utilities/ostream.hpp"
 
 ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
 
@@ -359,31 +360,29 @@
   java_lang_Class::set_fixup_module_field_list(NULL);
 }
 
-#ifndef PRODUCT
-void ModuleEntryTable::print() {
-  tty->print_cr("Module Entry Table (table_size=%d, entries=%d)",
-                table_size(), number_of_entries());
+void ModuleEntryTable::print(outputStream* st) {
+  st->print_cr("Module Entry Table (table_size=%d, entries=%d)",
+               table_size(), number_of_entries());
   for (int i = 0; i < table_size(); i++) {
     for (ModuleEntry* probe = bucket(i);
                               probe != NULL;
                               probe = probe->next()) {
-      probe->print();
+      probe->print(st);
     }
   }
 }
 
-void ModuleEntry::print() {
+void ModuleEntry::print(outputStream* st) {
   ResourceMark rm;
-  tty->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT,
-                p2i(this),
-                name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
-                p2i(module()),
-                loader()->loader_name(),
-                version() != NULL ? version()->as_C_string() : "NULL",
-                location() != NULL ? location()->as_C_string() : "NULL",
-                BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
+  st->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT,
+               p2i(this),
+               name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
+               p2i(module()),
+               loader()->loader_name(),
+               version() != NULL ? version()->as_C_string() : "NULL",
+               location() != NULL ? location()->as_C_string() : "NULL",
+               BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
 }
-#endif
 
 void ModuleEntryTable::verify() {
   int element_count = 0;
--- a/src/share/vm/classfile/moduleEntry.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/classfile/moduleEntry.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -33,6 +33,7 @@
 #include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.hpp"
+#include "utilities/ostream.hpp"
 
 #define UNNAMED_MODULE "Unnamed Module"
 
@@ -141,7 +142,7 @@
   void purge_reads();
   void delete_reads();
 
-  void print() PRODUCT_RETURN;
+  void print(outputStream* st = tty);
   void verify();
 };
 
@@ -223,7 +224,7 @@
   static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
   static void patch_javabase_entries(Handle module_handle);
 
-  void print() PRODUCT_RETURN;
+  void print(outputStream* st = tty);
   void verify();
 };
 
--- a/src/share/vm/classfile/packageEntry.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/classfile/packageEntry.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -32,6 +32,7 @@
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "utilities/ostream.hpp"
 
 // Return true if this package is exported to m.
 bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
@@ -265,28 +266,26 @@
   }
 }
 
-#ifndef PRODUCT
-void PackageEntryTable::print() {
-  tty->print_cr("Package Entry Table (table_size=%d, entries=%d)",
-                table_size(), number_of_entries());
+void PackageEntryTable::print(outputStream* st) {
+  st->print_cr("Package Entry Table (table_size=%d, entries=%d)",
+               table_size(), number_of_entries());
   for (int i = 0; i < table_size(); i++) {
     for (PackageEntry* probe = bucket(i);
                        probe != NULL;
                        probe = probe->next()) {
-      probe->print();
+      probe->print(st);
     }
   }
 }
 
-void PackageEntry::print() {
+void PackageEntry::print(outputStream* st) {
   ResourceMark rm;
-  tty->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
-                INT32_FORMAT " is_exported %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
-                p2i(this), name()->as_C_string(),
-                (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
-                _classpath_index, _is_exported, _is_exported_allUnnamed, p2i(next()));
+  st->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
+               INT32_FORMAT " is_exported %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
+               p2i(this), name()->as_C_string(),
+               (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
+               _classpath_index, _is_exported, _is_exported_allUnnamed, p2i(next()));
 }
-#endif
 
 void PackageEntryTable::verify() {
   int element_count = 0;
--- a/src/share/vm/classfile/packageEntry.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/classfile/packageEntry.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -29,6 +29,7 @@
 #include "oops/symbol.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/hashtable.hpp"
+#include "utilities/ostream.hpp"
 
 // A PackageEntry basically represents a Java package.  It contains:
 //   - Symbol* containing the package's name.
@@ -144,7 +145,7 @@
   void purge_qualified_exports();
   void delete_qualified_exports();
 
-  void print() PRODUCT_RETURN;
+  void print(outputStream* st = tty);
   void verify();
 };
 
@@ -195,7 +196,7 @@
   // purge dead weak references out of exported list
   void purge_all_package_exports();
 
-  void print() PRODUCT_RETURN;
+  void print(outputStream* st = tty);
   void verify();
 };
 
--- a/src/share/vm/gc/cms/compactibleFreeListSpace.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/cms/compactibleFreeListSpace.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -82,6 +82,8 @@
   template <typename SpaceType>
   friend void CompactibleSpace::scan_and_compact(SpaceType* space);
   template <typename SpaceType>
+  friend void CompactibleSpace::verify_up_to_first_dead(SpaceType* space);
+  template <typename SpaceType>
   friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp);
 
   // "Size" of chunks of work (executed during parallel remark phases
--- a/src/share/vm/gc/g1/g1CollectedHeap.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/g1/g1CollectedHeap.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -4452,7 +4452,6 @@
 }
 
 void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) {
-  double preserve_cm_referents_start = os::elapsedTime();
   // Any reference objects, in the collection set, that were 'discovered'
   // by the CM ref processor should have already been copied (either by
   // applying the external root copy closure to the discovered lists, or
@@ -4473,16 +4472,24 @@
   // objects discovered by the STW ref processor in case one of these
   // referents points to another object which is also referenced by an
   // object discovered by the STW ref processor.
-
-  uint no_of_gc_workers = workers()->active_workers();
-
-  G1ParPreserveCMReferentsTask keep_cm_referents(this,
-                                                 per_thread_states,
-                                                 no_of_gc_workers,
-                                                 _task_queues);
-  workers()->run_task(&keep_cm_referents);
-
-  g1_policy()->phase_times()->record_preserve_cm_referents_time_ms((os::elapsedTime() - preserve_cm_referents_start) * 1000.0);
+  double preserve_cm_referents_time = 0.0;
+
+  // To avoid spawning task when there is no work to do, check that
+  // a concurrent cycle is active and that some references have been
+  // discovered.
+  if (concurrent_mark()->cmThread()->during_cycle() &&
+      ref_processor_cm()->has_discovered_references()) {
+    double preserve_cm_referents_start = os::elapsedTime();
+    uint no_of_gc_workers = workers()->active_workers();
+    G1ParPreserveCMReferentsTask keep_cm_referents(this,
+                                                   per_thread_states,
+                                                   no_of_gc_workers,
+                                                   _task_queues);
+    workers()->run_task(&keep_cm_referents);
+    preserve_cm_referents_time = os::elapsedTime() - preserve_cm_referents_start;
+  }
+
+  g1_policy()->phase_times()->record_preserve_cm_referents_time_ms(preserve_cm_referents_time * 1000.0);
 }
 
 // Weak Reference processing during an evacuation pause (part 1).
--- a/src/share/vm/gc/g1/g1YoungGenSizer.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/g1/g1YoungGenSizer.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -25,12 +25,13 @@
 #include "precompiled.hpp"
 #include "gc/g1/g1YoungGenSizer.hpp"
 #include "gc/g1/heapRegion.hpp"
+#include "logging/log.hpp"
 
 G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
         _min_desired_young_length(0), _max_desired_young_length(0) {
   if (FLAG_IS_CMDLINE(NewRatio)) {
     if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) {
-      warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
+      log_warning(gc, ergo)("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
     } else {
       _sizer_kind = SizerNewRatio;
       _adaptive_size = false;
@@ -40,9 +41,9 @@
 
   if (NewSize > MaxNewSize) {
     if (FLAG_IS_CMDLINE(MaxNewSize)) {
-      warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
-              "A new max generation size of " SIZE_FORMAT "k will be used.",
-              NewSize/K, MaxNewSize/K, NewSize/K);
+      log_warning(gc, ergo)("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
+                            "A new max generation size of " SIZE_FORMAT "k will be used.",
+                            NewSize/K, MaxNewSize/K, NewSize/K);
     }
     MaxNewSize = NewSize;
   }
--- a/src/share/vm/gc/shared/referenceProcessor.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/shared/referenceProcessor.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -1090,6 +1090,15 @@
   return true;
 }
 
+bool ReferenceProcessor::has_discovered_references() {
+  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+    if (!_discovered_refs[i].is_empty()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Preclean the discovered references by removing those
 // whose referents are alive, and by marking from those that
 // are not active. These lists can be handled here
--- a/src/share/vm/gc/shared/referenceProcessor.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/shared/referenceProcessor.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -412,6 +412,9 @@
   // Discover a Reference object, using appropriate discovery criteria
   bool discover_reference(oop obj, ReferenceType rt);
 
+  // Has discovered references that need handling
+  bool has_discovered_references();
+
   // Process references found during GC (called by the garbage collector)
   ReferenceProcessorStats
   process_discovered_references(BoolObjectClosure*           is_alive,
--- a/src/share/vm/gc/shared/space.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/shared/space.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -411,22 +411,6 @@
   return compact_top;
 }
 
-
-bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words,
-                                        HeapWord* q, size_t deadlength) {
-  if (allowed_deadspace_words >= deadlength) {
-    allowed_deadspace_words -= deadlength;
-    CollectedHeap::fill_with_object(q, deadlength);
-    oop(q)->set_mark(oop(q)->mark()->set_marked());
-    assert((int) deadlength == oop(q)->size(), "bad filler object size");
-    // Recall that we required "q == compaction_top".
-    return true;
-  } else {
-    allowed_deadspace_words = 0;
-    return false;
-  }
-}
-
 void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) {
   scan_and_forward(this, cp);
 }
--- a/src/share/vm/gc/shared/space.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/shared/space.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -362,6 +362,12 @@
 
   inline size_t obj_size(const HeapWord* addr) const;
 
+  template <class SpaceType>
+  static inline void verify_up_to_first_dead(SpaceType* space) NOT_DEBUG_RETURN;
+
+  template <class SpaceType>
+  static inline void clear_empty_region(SpaceType* space);
+
 public:
   CompactibleSpace() :
    _compaction_top(NULL), _next_compaction_space(NULL) {}
@@ -455,16 +461,6 @@
     return end();
   }
 
-  // Requires "allowed_deadspace_words > 0", that "q" is the start of a
-  // free block of the given "word_len", and that "q", were it an object,
-  // would not move if forwarded.  If the size allows, fill the free
-  // block with an object, to prevent excessive compaction.  Returns "true"
-  // iff the free region was made deadspace, and modifies
-  // "allowed_deadspace_words" to reflect the number of available deadspace
-  // words remaining after this operation.
-  bool insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q,
-                        size_t word_len);
-
   // Below are template functions for scan_and_* algorithms (avoiding virtual calls).
   // The space argument should be a subclass of CompactibleSpace, implementing
   // scan_limit(), scanned_block_is_obj(), and scanned_block_size(),
--- a/src/share/vm/gc/shared/space.inline.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/gc/shared/space.inline.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -31,6 +31,7 @@
 #include "gc/shared/space.hpp"
 #include "gc/shared/spaceDecorator.hpp"
 #include "memory/universe.hpp"
+#include "oops/oopsHierarchy.hpp"
 #include "runtime/prefetch.inline.hpp"
 #include "runtime/safepoint.hpp"
 
@@ -75,11 +76,61 @@
   return oop(addr)->size();
 }
 
+class DeadSpacer : StackObj {
+  size_t _allowed_deadspace_words;
+  bool _active;
+  CompactibleSpace* _space;
+
+public:
+  DeadSpacer(CompactibleSpace* space) : _space(space), _allowed_deadspace_words(0) {
+    size_t ratio = _space->allowed_dead_ratio();
+    _active = ratio > 0;
+
+    if (_active) {
+      assert(!UseG1GC, "G1 should not be using dead space");
+
+      // We allow some amount of garbage towards the bottom of the space, so
+      // we don't start compacting before there is a significant gain to be made.
+      // Occasionally, we want to ensure a full compaction, which is determined
+      // by the MarkSweepAlwaysCompactCount parameter.
+      if ((MarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0) {
+        _allowed_deadspace_words = (space->capacity() * ratio / 100) / HeapWordSize;
+      } else {
+        _active = false;
+      }
+    }
+  }
+
+
+  bool insert_deadspace(HeapWord* dead_start, HeapWord* dead_end) {
+    if (!_active) {
+      return false;
+    }
+
+    size_t dead_length = pointer_delta(dead_end, dead_start);
+    if (_allowed_deadspace_words >= dead_length) {
+      _allowed_deadspace_words -= dead_length;
+      CollectedHeap::fill_with_object(dead_start, dead_length);
+      oop obj = oop(dead_start);
+      obj->set_mark(obj->mark()->set_marked());
+
+      assert(dead_length == (size_t)obj->size(), "bad filler object size");
+      log_develop_trace(gc, compaction)("Inserting object to dead space: " PTR_FORMAT ", " PTR_FORMAT ", " SIZE_FORMAT "b",
+          p2i(dead_start), p2i(dead_end), dead_length * HeapWordSize);
+
+      return true;
+    } else {
+      _active = false;
+      return false;
+    }
+  }
+
+};
+
 template <class SpaceType>
 inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp) {
   // Compute the new addresses for the live objects and store it in the mark
   // Used by universe::mark_sweep_phase2()
-  HeapWord* compact_top; // This is where we are currently compacting to.
 
   // We're sure to be here before any objects are compacted into this
   // space, so this is a good time to initialize this:
@@ -90,89 +141,73 @@
     assert(cp->threshold == NULL, "just checking");
     assert(cp->gen->first_compaction_space() == space, "just checking");
     cp->space = cp->gen->first_compaction_space();
-    compact_top = cp->space->bottom();
-    cp->space->set_compaction_top(compact_top);
     cp->threshold = cp->space->initialize_threshold();
-  } else {
-    compact_top = cp->space->compaction_top();
+    cp->space->set_compaction_top(cp->space->bottom());
   }
 
-  // We allow some amount of garbage towards the bottom of the space, so
-  // we don't start compacting before there is a significant gain to be made.
-  // Occasionally, we want to ensure a full compaction, which is determined
-  // by the MarkSweepAlwaysCompactCount parameter.
-  uint invocations = MarkSweep::total_invocations();
-  bool skip_dead = ((invocations % MarkSweepAlwaysCompactCount) != 0);
+  HeapWord* compact_top = cp->space->compaction_top(); // This is where we are currently compacting to.
 
-  size_t allowed_deadspace = 0;
-  if (skip_dead) {
-    const size_t ratio = space->allowed_dead_ratio();
-    allowed_deadspace = (space->capacity() * ratio / 100) / HeapWordSize;
-  }
+  DeadSpacer dead_spacer(space);
 
-  HeapWord* q = space->bottom();
-  HeapWord* t = space->scan_limit();
-
-  HeapWord*  end_of_live= q;            // One byte beyond the last byte of the last
-                                        // live object.
-  HeapWord*  first_dead = space->end(); // The first dead object.
+  HeapWord*  end_of_live = space->bottom();  // One byte beyond the last byte of the last live object.
+  HeapWord*  first_dead = NULL; // The first dead object.
 
   const intx interval = PrefetchScanIntervalInBytes;
 
-  while (q < t) {
-    assert(!space->scanned_block_is_obj(q) ||
-           oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() ||
-           oop(q)->mark()->has_bias_pattern(),
+  HeapWord* cur_obj = space->bottom();
+  HeapWord* scan_limit = space->scan_limit();
+
+  while (cur_obj < scan_limit) {
+    assert(!space->scanned_block_is_obj(cur_obj) ||
+           oop(cur_obj)->mark()->is_marked() || oop(cur_obj)->mark()->is_unlocked() ||
+           oop(cur_obj)->mark()->has_bias_pattern(),
            "these are the only valid states during a mark sweep");
-    if (space->scanned_block_is_obj(q) && oop(q)->is_gc_marked()) {
-      // prefetch beyond q
-      Prefetch::write(q, interval);
-      size_t size = space->scanned_block_size(q);
-      compact_top = cp->space->forward(oop(q), size, cp, compact_top);
-      q += size;
-      end_of_live = q;
+    if (space->scanned_block_is_obj(cur_obj) && oop(cur_obj)->is_gc_marked()) {
+      // prefetch beyond cur_obj
+      Prefetch::write(cur_obj, interval);
+      size_t size = space->scanned_block_size(cur_obj);
+      compact_top = cp->space->forward(oop(cur_obj), size, cp, compact_top);
+      cur_obj += size;
+      end_of_live = cur_obj;
     } else {
       // run over all the contiguous dead objects
-      HeapWord* end = q;
+      HeapWord* end = cur_obj;
       do {
         // prefetch beyond end
         Prefetch::write(end, interval);
         end += space->scanned_block_size(end);
-      } while (end < t && (!space->scanned_block_is_obj(end) || !oop(end)->is_gc_marked()));
+      } while (end < scan_limit && (!space->scanned_block_is_obj(end) || !oop(end)->is_gc_marked()));
 
       // see if we might want to pretend this object is alive so that
       // we don't have to compact quite as often.
-      if (allowed_deadspace > 0 && q == compact_top) {
-        size_t sz = pointer_delta(end, q);
-        if (space->insert_deadspace(allowed_deadspace, q, sz)) {
-          compact_top = cp->space->forward(oop(q), sz, cp, compact_top);
-          q = end;
-          end_of_live = end;
-          continue;
+      if (cur_obj == compact_top && dead_spacer.insert_deadspace(cur_obj, end)) {
+        oop obj = oop(cur_obj);
+        compact_top = cp->space->forward(obj, obj->size(), cp, compact_top);
+        end_of_live = end;
+      } else {
+        // otherwise, it really is a free region.
+
+        // cur_obj is a pointer to a dead object. Use this dead memory to store a pointer to the next live object.
+        *(HeapWord**)cur_obj = end;
+
+        // see if this is the first dead region.
+        if (first_dead == NULL) {
+          first_dead = cur_obj;
         }
       }
 
-      // otherwise, it really is a free region.
-
-      // q is a pointer to a dead object. Use this dead memory to store a pointer to the next live object.
-      (*(HeapWord**)q) = end;
-
-      // see if this is the first dead region.
-      if (q < first_dead) {
-        first_dead = q;
-      }
-
       // move on to the next object
-      q = end;
+      cur_obj = end;
     }
   }
 
-  assert(q == t, "just checking");
+  assert(cur_obj == scan_limit, "just checking");
   space->_end_of_live = end_of_live;
-  if (end_of_live < first_dead) {
-    first_dead = end_of_live;
+  if (first_dead != NULL) {
+    space->_first_dead = first_dead;
+  } else {
+    space->_first_dead = end_of_live;
   }
-  space->_first_dead = first_dead;
 
   // save the compaction_top of the compaction space.
   cp->space->set_compaction_top(compact_top);
@@ -183,127 +218,58 @@
   // adjust all the interior pointers to point at the new locations of objects
   // Used by MarkSweep::mark_sweep_phase3()
 
-  HeapWord* q = space->bottom();
-  HeapWord* t = space->_end_of_live;  // Established by "prepare_for_compaction".
+  HeapWord* cur_obj = space->bottom();
+  HeapWord* const end_of_live = space->_end_of_live;  // Established by "scan_and_forward".
+  HeapWord* const first_dead = space->_first_dead;    // Established by "scan_and_forward".
 
-  assert(space->_first_dead <= space->_end_of_live, "Stands to reason, no?");
+  assert(first_dead <= end_of_live, "Stands to reason, no?");
 
-  if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) {
-    // we have a chunk of the space which hasn't moved and we've
-    // reinitialized the mark word during the previous pass, so we can't
-    // use is_gc_marked for the traversal.
-    HeapWord* end = space->_first_dead;
+  const intx interval = PrefetchScanIntervalInBytes;
 
-    while (q < end) {
-      // I originally tried to conjoin "block_start(q) == q" to the
-      // assertion below, but that doesn't work, because you can't
-      // accurately traverse previous objects to get to the current one
-      // after their pointers have been
-      // updated, until the actual compaction is done.  dld, 4/00
-      assert(space->block_is_obj(q), "should be at block boundaries, and should be looking at objs");
-
+  debug_only(HeapWord* prev_obj = NULL);
+  while (cur_obj < end_of_live) {
+    Prefetch::write(cur_obj, interval);
+    if (cur_obj < first_dead || oop(cur_obj)->is_gc_marked()) {
+      // cur_obj is alive
       // point all the oops to the new location
-      size_t size = MarkSweep::adjust_pointers(oop(q));
+      size_t size = MarkSweep::adjust_pointers(oop(cur_obj));
       size = space->adjust_obj_size(size);
-
-      q += size;
-    }
-
-    if (space->_first_dead == t) {
-      q = t;
+      debug_only(prev_obj = cur_obj);
+      cur_obj += size;
     } else {
-      // The first dead object is no longer an object. At that memory address,
-      // there is a pointer to the first live object that the previous phase found.
-      q = *((HeapWord**)(space->_first_dead));
+      debug_only(prev_obj = cur_obj);
+      // cur_obj is not a live object, instead it points at the next live object
+      cur_obj = *(HeapWord**)cur_obj;
+      assert(cur_obj > prev_obj, "we should be moving forward through memory, cur_obj: " PTR_FORMAT ", prev_obj: " PTR_FORMAT, p2i(cur_obj), p2i(prev_obj));
     }
   }
 
-  const intx interval = PrefetchScanIntervalInBytes;
-
-  debug_only(HeapWord* prev_q = NULL);
-  while (q < t) {
-    // prefetch beyond q
-    Prefetch::write(q, interval);
-    if (oop(q)->is_gc_marked()) {
-      // q is alive
-      // point all the oops to the new location
-      size_t size = MarkSweep::adjust_pointers(oop(q));
-      size = space->adjust_obj_size(size);
-      debug_only(prev_q = q);
-      q += size;
-    } else {
-      debug_only(prev_q = q);
-      // q is not a live object, instead it points at the next live object
-      q = *(HeapWord**)q;
-      assert(q > prev_q, "we should be moving forward through memory, q: " PTR_FORMAT ", prev_q: " PTR_FORMAT, p2i(q), p2i(prev_q));
-    }
-  }
-
-  assert(q == t, "just checking");
+  assert(cur_obj == end_of_live, "just checking");
 }
 
+#ifdef ASSERT
 template <class SpaceType>
-inline void CompactibleSpace::scan_and_compact(SpaceType* space) {
-  // Copy all live objects to their new location
-  // Used by MarkSweep::mark_sweep_phase4()
+inline void CompactibleSpace::verify_up_to_first_dead(SpaceType* space) {
+  HeapWord* cur_obj = space->bottom();
 
-  HeapWord*       q = space->bottom();
-  HeapWord* const t = space->_end_of_live;
-  debug_only(HeapWord* prev_q = NULL);
+  if (cur_obj < space->_end_of_live && space->_first_dead > cur_obj && !oop(cur_obj)->is_gc_marked()) {
+     // we have a chunk of the space which hasn't moved and we've reinitialized
+     // the mark word during the previous pass, so we can't use is_gc_marked for
+     // the traversal.
+     HeapWord* prev_obj = NULL;
 
-  if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) {
-    #ifdef ASSERT // Debug only
-      // we have a chunk of the space which hasn't moved and we've reinitialized
-      // the mark word during the previous pass, so we can't use is_gc_marked for
-      // the traversal.
-      HeapWord* const end = space->_first_dead;
+     while (cur_obj < space->_first_dead) {
+       size_t size = space->obj_size(cur_obj);
+       assert(!oop(cur_obj)->is_gc_marked(), "should be unmarked (special dense prefix handling)");
+       prev_obj = cur_obj;
+       cur_obj += size;
+     }
+  }
+}
+#endif
 
-      while (q < end) {
-        size_t size = space->obj_size(q);
-        assert(!oop(q)->is_gc_marked(), "should be unmarked (special dense prefix handling)");
-        prev_q = q;
-        q += size;
-      }
-    #endif
-
-    if (space->_first_dead == t) {
-      q = t;
-    } else {
-      // $$$ Funky
-      q = (HeapWord*) oop(space->_first_dead)->mark()->decode_pointer();
-    }
-  }
-
-  const intx scan_interval = PrefetchScanIntervalInBytes;
-  const intx copy_interval = PrefetchCopyIntervalInBytes;
-  while (q < t) {
-    if (!oop(q)->is_gc_marked()) {
-      // mark is pointer to next marked oop
-      debug_only(prev_q = q);
-      q = (HeapWord*) oop(q)->mark()->decode_pointer();
-      assert(q > prev_q, "we should be moving forward through memory");
-    } else {
-      // prefetch beyond q
-      Prefetch::read(q, scan_interval);
-
-      // size and destination
-      size_t size = space->obj_size(q);
-      HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee();
-
-      // prefetch beyond compaction_top
-      Prefetch::write(compaction_top, copy_interval);
-
-      // copy object and reinit its mark
-      assert(q != compaction_top, "everything in this pass should be moving");
-      Copy::aligned_conjoint_words(q, compaction_top, size);
-      oop(compaction_top)->init_mark();
-      assert(oop(compaction_top)->klass() != NULL, "should have a class");
-
-      debug_only(prev_q = q);
-      q += size;
-    }
-  }
-
+template <class SpaceType>
+inline void CompactibleSpace::clear_empty_region(SpaceType* space) {
   // Let's remember if we were empty before we did the compaction.
   bool was_empty = space->used_region().is_empty();
   // Reset space after compaction is complete
@@ -320,6 +286,65 @@
   }
 }
 
+template <class SpaceType>
+inline void CompactibleSpace::scan_and_compact(SpaceType* space) {
+  // Copy all live objects to their new location
+  // Used by MarkSweep::mark_sweep_phase4()
+
+  verify_up_to_first_dead(space);
+
+  HeapWord* const end_of_live = space->_end_of_live;
+
+  assert(space->_first_dead <= end_of_live, "Invariant. _first_dead: " PTR_FORMAT " <= end_of_live: " PTR_FORMAT, p2i(space->_first_dead), p2i(end_of_live));
+  if (space->_first_dead == end_of_live && !oop(space->bottom())->is_gc_marked()) {
+    // Nothing to compact. The space is either empty or all live object should be left in place.
+    clear_empty_region(space);
+    return;
+  }
+
+  const intx scan_interval = PrefetchScanIntervalInBytes;
+  const intx copy_interval = PrefetchCopyIntervalInBytes;
+
+  assert(space->bottom() < end_of_live, "bottom: " PTR_FORMAT " should be < end_of_live: " PTR_FORMAT, p2i(space->bottom()), p2i(end_of_live));
+  HeapWord* cur_obj = space->bottom();
+  if (space->_first_dead > cur_obj && !oop(cur_obj)->is_gc_marked()) {
+    // All object before _first_dead can be skipped. They should not be moved.
+    // A pointer to the first live object is stored at the memory location for _first_dead.
+    cur_obj = *(HeapWord**)(space->_first_dead);
+  }
+
+  debug_only(HeapWord* prev_obj = NULL);
+  while (cur_obj < end_of_live) {
+    if (!oop(cur_obj)->is_gc_marked()) {
+      debug_only(prev_obj = cur_obj);
+      // The first word of the dead object contains a pointer to the next live object or end of space.
+      cur_obj = *(HeapWord**)cur_obj;
+      assert(cur_obj > prev_obj, "we should be moving forward through memory");
+    } else {
+      // prefetch beyond q
+      Prefetch::read(cur_obj, scan_interval);
+
+      // size and destination
+      size_t size = space->obj_size(cur_obj);
+      HeapWord* compaction_top = (HeapWord*)oop(cur_obj)->forwardee();
+
+      // prefetch beyond compaction_top
+      Prefetch::write(compaction_top, copy_interval);
+
+      // copy object and reinit its mark
+      assert(cur_obj != compaction_top, "everything in this pass should be moving");
+      Copy::aligned_conjoint_words(cur_obj, compaction_top, size);
+      oop(compaction_top)->init_mark();
+      assert(oop(compaction_top)->klass() != NULL, "should have a class");
+
+      debug_only(prev_obj = cur_obj);
+      cur_obj += size;
+    }
+  }
+
+  clear_empty_region(space);
+}
+
 size_t ContiguousSpace::scanned_block_size(const HeapWord* addr) const {
   return oop(addr)->size();
 }
--- a/src/share/vm/memory/allocation.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/memory/allocation.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -143,8 +143,9 @@
   mtTest              = 0x0D,  // Test type for verifying NMT
   mtTracing           = 0x0E,  // memory used for Tracing
   mtLogging           = 0x0F,  // memory for logging
-  mtNone              = 0x10,  // undefined
-  mt_number_of_types  = 0x11   // number of memory types (mtDontTrack
+  mtArguments         = 0x10,  // memory for argument processing
+  mtNone              = 0x11,  // undefined
+  mt_number_of_types  = 0x12   // number of memory types (mtDontTrack
                                  // is not included as validate type)
 };
 
--- a/src/share/vm/prims/jvmtiExport.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/prims/jvmtiExport.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -2260,7 +2260,7 @@
     if (env->is_enabled(JVMTI_EVENT_VM_OBJECT_ALLOC)) {
       EVT_TRACE(JVMTI_EVENT_VM_OBJECT_ALLOC, ("JVMTI [%s] Evt vmobject alloc sent %s",
                                          JvmtiTrace::safe_get_thread_name(thread),
-                                         object==NULL? "NULL" : java_lang_Class::as_Klass(object)->external_name()));
+                                         object==NULL? "NULL" : object->klass()->external_name()));
 
       JvmtiVMObjectAllocEventMark jem(thread, h());
       JvmtiJavaThreadEventTransition jet(thread);
--- a/src/share/vm/runtime/arguments.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -698,7 +698,7 @@
   assert(total_len > 0, "empty sysclasspath not allowed");
 
   // Copy the _items to a single string.
-  char* cp = NEW_C_HEAP_ARRAY(char, total_len, mtInternal);
+  char* cp = NEW_C_HEAP_ARRAY(char, total_len, mtArguments);
   char* cp_tmp = cp;
   for (i = 0; i < _bcp_nitems; ++i) {
     if (_items[i] != NULL) {
@@ -719,7 +719,7 @@
   assert(str != NULL, "just checking");
   if (path == NULL) {
     size_t len = strlen(str) + 1;
-    cp = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+    cp = NEW_C_HEAP_ARRAY(char, len, mtArguments);
     memcpy(cp, str, len);                       // copy the trailing null
   } else {
     const char separator = *os::path_separator();
@@ -728,7 +728,7 @@
     size_t len = old_len + str_len + 2;
 
     if (prepend) {
-      cp = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+      cp = NEW_C_HEAP_ARRAY(char, len, mtArguments);
       char* cp_tmp = cp;
       memcpy(cp_tmp, str, str_len);
       cp_tmp += str_len;
@@ -736,7 +736,7 @@
       memcpy(++cp_tmp, path, old_len + 1);      // copy the trailing null
       FREE_C_HEAP_ARRAY(char, path);
     } else {
-      cp = REALLOC_C_HEAP_ARRAY(char, path, len, mtInternal);
+      cp = REALLOC_C_HEAP_ARRAY(char, path, len, mtArguments);
       char* cp_tmp = cp + old_len;
       *cp_tmp = separator;
       memcpy(++cp_tmp, str, str_len + 1);       // copy the trailing null
@@ -758,7 +758,7 @@
 
   /* Scan the directory for jars/zips, appending them to path. */
   struct dirent *entry;
-  char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal);
+  char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtArguments);
   while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) {
     const char* name = entry->d_name;
     const char* ext = name + strlen(name) - 4;
@@ -766,7 +766,7 @@
       (os::file_name_strcmp(ext, ".jar") == 0 ||
        os::file_name_strcmp(ext, ".zip") == 0);
     if (isJarOrZip) {
-      char* jarpath = NEW_C_HEAP_ARRAY(char, directory_len + 2 + strlen(name), mtInternal);
+      char* jarpath = NEW_C_HEAP_ARRAY(char, directory_len + 2 + strlen(name), mtArguments);
       sprintf(jarpath, "%s%s%s", directory, dir_sep, name);
       path = add_to_path(path, jarpath, false);
       FREE_C_HEAP_ARRAY(char, jarpath);
@@ -943,7 +943,7 @@
   } else if (new_len == 0) {
     value = old_value;
   } else {
-    char* buf = NEW_C_HEAP_ARRAY(char, old_len + 1 + new_len + 1, mtInternal);
+    char* buf = NEW_C_HEAP_ARRAY(char, old_len + 1 + new_len + 1, mtArguments);
     // each new setting adds another LINE to the switch:
     sprintf(buf, "%s\n%s", old_value, new_value);
     value = buf;
@@ -1134,9 +1134,9 @@
 
   // expand the array and add arg to the last element
   if (*bldarray == NULL) {
-    *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtInternal);
+    *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtArguments);
   } else {
-    *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtInternal);
+    *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtArguments);
   }
   (*bldarray)[*count] = os::strdup_check_oom(arg);
   *count = new_count;
@@ -1400,7 +1400,7 @@
     // property have a value, thus extract it and save to the
     // allocated string
     size_t key_len = eq - prop;
-    char* tmp_key = AllocateHeap(key_len + 1, mtInternal);
+    char* tmp_key = AllocateHeap(key_len + 1, mtArguments);
 
     strncpy(tmp_key, prop, key_len);
     tmp_key[key_len] = '\0';
@@ -1422,7 +1422,7 @@
   } else {
     if (strcmp(key, "sun.java.command") == 0) {
       char *old_java_command = _java_command;
-      _java_command = os::strdup_check_oom(value, mtInternal);
+      _java_command = os::strdup_check_oom(value, mtArguments);
       if (old_java_command != NULL) {
         os::free(old_java_command);
       }
@@ -1430,7 +1430,7 @@
       const char* old_java_vendor_url_bug = _java_vendor_url_bug;
       // save it in _java_vendor_url_bug, so JVM fatal error handler can access
       // its value without going through the property list or making a Java call.
-      _java_vendor_url_bug = os::strdup_check_oom(value, mtInternal);
+      _java_vendor_url_bug = os::strdup_check_oom(value, mtArguments);
       if (old_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) {
         assert(old_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL");
         os::free((void *)old_java_vendor_url_bug);
@@ -1458,7 +1458,7 @@
   if (old_value != NULL) {
     buf_len += strlen(old_value) + 1;
   }
-  char* new_value = AllocateHeap(buf_len, mtInternal);
+  char* new_value = AllocateHeap(buf_len, mtArguments);
   if (new_value == NULL) {
     return false;
   }
@@ -2852,13 +2852,13 @@
       if (tail != NULL) {
         const char* pos = strchr(tail, ':');
         size_t len = (pos == NULL) ? strlen(tail) : pos - tail;
-        char* name = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len);
+        char* name = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len + 1, mtArguments), tail, len);
         name[len] = '\0';
 
         char *options = NULL;
         if(pos != NULL) {
           size_t len2 = strlen(pos+1) + 1; // options start after ':'.  Final zero must be copied.
-          options = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len2, mtInternal), pos+1, len2);
+          options = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len2, mtArguments), pos+1, len2);
         }
 #if !INCLUDE_JVMTI
         if (strcmp(name, "jdwp") == 0) {
@@ -2875,12 +2875,12 @@
       if(tail != NULL) {
         const char* pos = strchr(tail, '=');
         size_t len = (pos == NULL) ? strlen(tail) : pos - tail;
-        char* name = strncpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len);
+        char* name = strncpy(NEW_C_HEAP_ARRAY(char, len + 1, mtArguments), tail, len);
         name[len] = '\0';
 
         char *options = NULL;
         if(pos != NULL) {
-          options = os::strdup_check_oom(pos + 1, mtInternal);
+          options = os::strdup_check_oom(pos + 1, mtArguments);
         }
 #if !INCLUDE_JVMTI
         if (valid_jdwp_agent(name, is_absolute_path)) {
@@ -2899,7 +2899,7 @@
       return JNI_ERR;
 #else
       if (tail != NULL) {
-        char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail);
+        char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtArguments), tail);
         add_init_agent("instrument", options, false);
         // java agents need module java.instrument. Also -addmods ALL-SYSTEM because
         // the java agent is in the unmamed module of the application class loader
@@ -3201,7 +3201,7 @@
             size_t len = strlen(patch_dirs[x]);
             if (len != 0) { // Ignore empty strings.
               len += 11; // file_sep + "java.base" + null terminator.
-              char* dir = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+              char* dir = NEW_C_HEAP_ARRAY(char, len, mtArguments);
               jio_snprintf(dir, len, "%s%cjava.base", patch_dirs[x], file_sep);
 
               // See if Xpatch module path exists.
@@ -3507,7 +3507,7 @@
       src ++;
     }
 
-    char* copy = os::strdup_check_oom(src, mtInternal);
+    char* copy = os::strdup_check_oom(src, mtArguments);
 
     // trim all trailing empty paths
     for (char* tail = copy + strlen(copy) - 1; tail >= copy && *tail == separator; tail--) {
@@ -3531,7 +3531,7 @@
   if (dir == NULL) return false;
 
   struct dirent *entry;
-  char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal);
+  char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtArguments);
   bool hasJarFile = false;
   while (!hasJarFile && (entry = os::readdir(dir, (dirent *) dbuf)) != NULL) {
     const char* name = entry->d_name;
@@ -3557,7 +3557,7 @@
       }
       path = end;
     } else {
-      char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal);
+      char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtArguments);
       memcpy(dirpath, path, tmp_end - path);
       dirpath[tmp_end - path] = '\0';
       if (has_jar_files(dirpath)) {
@@ -3729,7 +3729,7 @@
   jint set_args(GrowableArray<JavaVMOption>* options) {
     _is_set = true;
     JavaVMOption* options_arr = NEW_C_HEAP_ARRAY_RETURN_NULL(
-        JavaVMOption, options->length(), mtInternal);
+        JavaVMOption, options->length(), mtArguments);
     if (options_arr == NULL) {
       return JNI_ENOMEM;
     }
@@ -3784,7 +3784,7 @@
     assert(vm_options_file_pos != -1, "vm_options_file_pos should be set");
 
     int length = args->nOptions + args_to_insert->nOptions - 1;
-    GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtInternal)
+    GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtArguments)
               GrowableArray<JavaVMOption>(length, true);    // Construct new option array
     for (int i = 0; i < args->nOptions; i++) {
       if (i == vm_options_file_pos) {
@@ -3861,7 +3861,7 @@
   // '+ 1' for NULL termination even with max bytes
   size_t bytes_alloc = stbuf.st_size + 1;
 
-  char *buf = NEW_C_HEAP_ARRAY_RETURN_NULL(char, bytes_alloc, mtInternal);
+  char *buf = NEW_C_HEAP_ARRAY_RETURN_NULL(char, bytes_alloc, mtArguments);
   if (NULL == buf) {
     jio_fprintf(defaultStream::error_stream(),
                 "Could not allocate read buffer for options file parse\n");
@@ -3898,7 +3898,7 @@
 }
 
 jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_t buf_len, ScopedVMInitArgs* vm_args) {
-  GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JavaVMOption>(2, true);    // Construct option array
+  GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<JavaVMOption>(2, true);    // Construct option array
 
   // some pointers to help with parsing
   char *buffer_end = buffer + buf_len;
@@ -4002,13 +4002,13 @@
     size_t jvm_path_len = strlen(jvm_path);
     size_t file_sep_len = strlen(os::file_separator());
     const size_t len = jvm_path_len + file_sep_len + 20;
-    shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal);
+    shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtArguments);
     if (shared_archive_path != NULL) {
       jio_snprintf(shared_archive_path, len, "%s%sclasses.jsa",
         jvm_path, os::file_separator());
     }
   } else {
-    shared_archive_path = os::strdup_check_oom(SharedArchiveFile, mtInternal);
+    shared_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
   }
   return shared_archive_path;
 }
--- a/src/share/vm/runtime/arguments.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/arguments.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -47,7 +47,7 @@
 // PathString is used as the underlying value container for a
 // SystemProperty and for the string that represents the system
 // boot class path, Arguments::_system_boot_class_path.
-class PathString : public CHeapObj<mtInternal> {
+class PathString : public CHeapObj<mtArguments> {
  protected:
   char*           _value;
  public:
@@ -57,7 +57,7 @@
     if (_value != NULL) {
       FreeHeap(_value);
     }
-    _value = AllocateHeap(strlen(value)+1, mtInternal);
+    _value = AllocateHeap(strlen(value)+1, mtArguments);
     assert(_value != NULL, "Unable to allocate space for new path value");
     if (_value != NULL) {
       strcpy(_value, value);
@@ -76,7 +76,7 @@
       if (_value != NULL) {
         len += strlen(_value);
       }
-      sp = AllocateHeap(len+2, mtInternal);
+      sp = AllocateHeap(len+2, mtArguments);
       assert(sp != NULL, "Unable to allocate space for new append path value");
       if (sp != NULL) {
         if (_value != NULL) {
@@ -97,7 +97,7 @@
     if (value == NULL) {
       _value = NULL;
     } else {
-      _value = AllocateHeap(strlen(value)+1, mtInternal);
+      _value = AllocateHeap(strlen(value)+1, mtArguments);
       strcpy(_value, value);
     }
   }
@@ -143,7 +143,7 @@
     if (key == NULL) {
       _key = NULL;
     } else {
-      _key = AllocateHeap(strlen(key)+1, mtInternal);
+      _key = AllocateHeap(strlen(key)+1, mtArguments);
       strcpy(_key, key);
     }
     _next = NULL;
@@ -154,7 +154,7 @@
 
 
 // For use by -agentlib, -agentpath and -Xrun
-class AgentLibrary : public CHeapObj<mtInternal> {
+class AgentLibrary : public CHeapObj<mtArguments> {
   friend class AgentLibraryList;
 public:
   // Is this library valid or not. Don't rely on os_lib == NULL as statically
@@ -189,12 +189,12 @@
 
   // Constructor
   AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) {
-    _name = AllocateHeap(strlen(name)+1, mtInternal);
+    _name = AllocateHeap(strlen(name)+1, mtArguments);
     strcpy(_name, name);
     if (options == NULL) {
       _options = NULL;
     } else {
-      _options = AllocateHeap(strlen(options)+1, mtInternal);
+      _options = AllocateHeap(strlen(options)+1, mtArguments);
       strcpy(_options, options);
     }
     _is_absolute_path = is_absolute_path;
--- a/src/share/vm/runtime/commandLineFlagConstraintList.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/commandLineFlagConstraintList.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -226,7 +226,7 @@
 
 // Check the ranges of all flags that have them or print them out and exit if requested
 void CommandLineFlagConstraintList::init(void) {
-  _constraints = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<CommandLineFlagConstraint*>(INITIAL_CONSTRAINTS_SIZE, true);
+  _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<CommandLineFlagConstraint*>(INITIAL_CONSTRAINTS_SIZE, true);
 
   emit_constraint_no(NULL RUNTIME_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
                                         EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
--- a/src/share/vm/runtime/commandLineFlagConstraintList.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/commandLineFlagConstraintList.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -48,7 +48,7 @@
 typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(size_t value, bool verbose);
 typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(double value, bool verbose);
 
-class CommandLineFlagConstraint : public CHeapObj<mtInternal> {
+class CommandLineFlagConstraint : public CHeapObj<mtArguments> {
 public:
   // During VM initialization, constraint validation will be done order of ConstraintType.
   enum ConstraintType {
--- a/src/share/vm/runtime/commandLineFlagRangeList.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/commandLineFlagRangeList.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -292,7 +292,7 @@
 // Check the ranges of all flags that have them
 void CommandLineFlagRangeList::init(void) {
 
-  _ranges = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<CommandLineFlagRange*>(INITIAL_RANGES_SIZE, true);
+  _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<CommandLineFlagRange*>(INITIAL_RANGES_SIZE, true);
 
   emit_range_no(NULL RUNTIME_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
                                    EMIT_RANGE_PD_DEVELOPER_FLAG,
--- a/src/share/vm/runtime/commandLineFlagRangeList.hpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/commandLineFlagRangeList.hpp	Fri Apr 15 17:17:58 2016 +0200
@@ -44,7 +44,7 @@
   static void print(bool verbose, const char* msg, ...);
 };
 
-class CommandLineFlagRange : public CHeapObj<mtInternal> {
+class CommandLineFlagRange : public CHeapObj<mtArguments> {
 private:
   const char* _name;
 public:
--- a/src/share/vm/runtime/globals.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/runtime/globals.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -1292,7 +1292,7 @@
   const size_t length = Flag::numFlags - 1;
 
   // Sort
-  Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal);
+  Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments);
   for (size_t i = 0; i < length; i++) {
     array[i] = &flagTable[i];
   }
@@ -1326,7 +1326,7 @@
   const size_t length = Flag::numFlags - 1;
 
   // Sort
-  Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal);
+  Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments);
   for (size_t i = 0; i < length; i++) {
     array[i] = &flagTable[i];
   }
--- a/src/share/vm/services/nmtCommon.cpp	Thu Apr 14 19:55:39 2016 -0700
+++ b/src/share/vm/services/nmtCommon.cpp	Fri Apr 15 17:17:58 2016 +0200
@@ -41,6 +41,7 @@
   "Test",
   "Tracing",
   "Logging",
+  "Arguments",
   "Unknown"
 };
 
--- a/test/TEST.groups	Thu Apr 14 19:55:39 2016 -0700
+++ b/test/TEST.groups	Fri Apr 15 17:17:58 2016 +0200
@@ -338,6 +338,7 @@
   sanity/ExecuteInternalVMTests.java \
   gc/ \
   -gc/g1/ \
+  -gc/stress \
   -gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java \
   -gc/cms/TestMBeanCMS.java \
   -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java
@@ -346,7 +347,7 @@
   sanity/ExecuteInternalVMTests.java
 
 hotspot_fast_gc_gcold = \
-  stress/gc/TestGCOld.java
+  gc/stress/TestGCOld.java
 
 hotspot_fast_runtime = \
   runtime/ \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestGCOld.java	Fri Apr 15 17:17:58 2016 +0200
@@ -0,0 +1,417 @@
+/*
+* Copyright (c) 2015, 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 TestGCOld
+ * @key gc
+ * @key stress
+ * @requires vm.gc=="null"
+ * @summary Stress the GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm -Xmx384M -XX:+UseSerialGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC -XX:-UseParallelOldGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseConcMarkSweepGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseG1GC TestGCOld 50 1 20 10 10000
+ */
+
+import java.text.*;
+import java.util.Random;
+
+class TreeNode {
+    public TreeNode left, right;
+    public int val;                // will always be the height of the tree
+}
+
+
+/* Args:
+   live-data-size: in megabytes (approximate, will be rounded down).
+   work: units of mutator non-allocation work per byte allocated,
+     (in unspecified units.  This will affect the promotion rate
+      printed at the end of the run: more mutator work per step implies
+      fewer steps per second implies fewer bytes promoted per second.)
+   short/long ratio: ratio of short-lived bytes allocated to long-lived
+      bytes allocated.
+   pointer mutation rate: number of pointer mutations per step.
+   steps: number of steps to do.
+*/
+
+public class TestGCOld {
+
+  // Command-line parameters.
+
+  private static int size, workUnits, promoteRate, ptrMutRate, steps;
+
+  // Constants.
+
+  private static final int MEG = 1000000;
+  private static final int INSIGNIFICANT = 999; // this many bytes don't matter
+  private static final int BYTES_PER_WORD = 4;
+  private static final int BYTES_PER_NODE = 20; // bytes per TreeNode
+  private static final int WORDS_DEAD = 100;    // size of young garbage object
+
+  private final static int treeHeight = 14;
+  private final static long treeSize = heightToBytes(treeHeight);
+
+  private static final String msg1
+    = "Usage: java TestGCOld <size> <work> <ratio> <mutation> <steps>";
+  private static final String msg2
+    = "  where <size> is the live storage in megabytes";
+  private static final String msg3
+    = "        <work> is the mutator work per step (arbitrary units)";
+  private static final String msg4
+    = "        <ratio> is the ratio of short-lived to long-lived allocation";
+  private static final String msg5
+    = "        <mutation> is the mutations per step";
+  private static final String msg6
+    = "        <steps> is the number of steps";
+
+  // Counters (and global variables that discourage optimization)
+
+  private static long youngBytes = 0;    // total young bytes allocated
+  private static long nodes = 0;         // total tree nodes allocated
+  private static long actuallyMut = 0;   // pointer mutations in old trees
+  private static long mutatorSum = 0;    // checksum to discourage optimization
+  public static int[] aexport;           // exported array to discourage opt
+
+  // Global variables.
+
+  private static TreeNode[] trees;
+  private static int where = 0;               // roving index into trees
+  private static Random rnd = new Random();
+
+  // Returns the height of the given tree.
+
+  private static int height (TreeNode t) {
+    if (t == null) {
+      return 0;
+    }
+    else {
+      return 1 + Math.max (height (t.left), height (t.right));
+    }
+  }
+
+  // Returns the length of the shortest path in the given tree.
+
+  private static int shortestPath (TreeNode t) {
+    if (t == null) {
+      return 0;
+    }
+    else {
+      return 1 + Math.min (shortestPath (t.left), shortestPath (t.right));
+    }
+  }
+
+  // Returns the number of nodes in a balanced tree of the given height.
+
+  private static long heightToNodes (int h) {
+    if (h == 0) {
+      return 0;
+    }
+    else {
+      long n = 1;
+      while (h > 1) {
+        n = n + n;
+        h = h - 1;
+      }
+      return n + n - 1;
+    }
+  }
+
+  // Returns the number of bytes in a balanced tree of the given height.
+
+  private static long heightToBytes (int h) {
+    return BYTES_PER_NODE * heightToNodes (h);
+  }
+
+  // Returns the height of the largest balanced tree
+  // that has no more than the given number of nodes.
+
+  private static int nodesToHeight (long nodes) {
+    int h = 1;
+    long n = 1;
+    while (n + n - 1 <= nodes) {
+      n = n + n;
+      h = h + 1;
+    }
+    return h - 1;
+  }
+
+  // Returns the height of the largest balanced tree
+  // that occupies no more than the given number of bytes.
+
+  private static int bytesToHeight (long bytes) {
+    return nodesToHeight (bytes / BYTES_PER_NODE);
+  }
+
+  // Returns a newly allocated balanced binary tree of height h.
+
+  private static TreeNode makeTree(int h) {
+    if (h == 0) return null;
+    else {
+      TreeNode res = new TreeNode();
+      nodes++;
+      res.left = makeTree(h-1);
+      res.right = makeTree(h-1);
+      res.val = h;
+      return res;
+    }
+  }
+
+  // Allocates approximately size megabytes of trees and stores
+  // them into a global array.
+
+  private static void init() {
+    int ntrees = (int) ((size * MEG) / treeSize);
+    trees = new TreeNode[ntrees];
+
+    System.err.println("Allocating " + ntrees + " trees.");
+    System.err.println("  (" + (ntrees * treeSize) + " bytes)");
+    for (int i = 0; i < ntrees; i++) {
+      trees[i] = makeTree(treeHeight);
+      // doYoungGenAlloc(promoteRate*ntrees*treeSize, WORDS_DEAD);
+    }
+    System.err.println("  (" + nodes + " nodes)");
+
+    /* Allow any in-progress GC to catch up... */
+    // try { Thread.sleep(20000); } catch (InterruptedException x) {}
+  }
+
+  // Confirms that all trees are balanced and have the correct height.
+
+  private static void checkTrees() {
+    int ntrees = trees.length;
+    for (int i = 0; i < ntrees; i++) {
+      TreeNode t = trees[i];
+      int h1 = height(t);
+      int h2 = shortestPath(t);
+      if ((h1 != treeHeight) || (h2 != treeHeight)) {
+        System.err.println("*****BUG: " + h1 + " " + h2);
+      }
+    }
+  }
+
+  // Called only by replaceTree (below) and by itself.
+
+  private static void replaceTreeWork(TreeNode full, TreeNode partial, boolean dir) {
+    boolean canGoLeft = full.left != null && full.left.val > partial.val;
+    boolean canGoRight = full.right != null && full.right.val > partial.val;
+    if (canGoLeft && canGoRight) {
+      if (dir)
+        replaceTreeWork(full.left, partial, !dir);
+      else
+        replaceTreeWork(full.right, partial, !dir);
+    } else if (!canGoLeft && !canGoRight) {
+      if (dir)
+        full.left = partial;
+      else
+        full.right = partial;
+    } else if (!canGoLeft) {
+      full.left = partial;
+    } else {
+      full.right = partial;
+    }
+  }
+
+  // Given a balanced tree full and a smaller balanced tree partial,
+  // replaces an appropriate subtree of full by partial, taking care
+  // to preserve the shape of the full tree.
+
+  private static void replaceTree(TreeNode full, TreeNode partial) {
+    boolean dir = (partial.val % 2) == 0;
+    actuallyMut++;
+    replaceTreeWork(full, partial, dir);
+  }
+
+  // Allocates approximately n bytes of long-lived storage,
+  // replacing oldest existing long-lived storage.
+
+  private static void oldGenAlloc(long n) {
+    int full = (int) (n / treeSize);
+    long partial = n % treeSize;
+    // System.out.println("In oldGenAlloc, doing " + full + " full trees "
+    // + "and one partial tree of size " + partial);
+    for (int i = 0; i < full; i++) {
+      trees[where++] = makeTree(treeHeight);
+      if (where == trees.length) where = 0;
+    }
+    while (partial > INSIGNIFICANT) {
+      int h = bytesToHeight(partial);
+      TreeNode newTree = makeTree(h);
+      replaceTree(trees[where++], newTree);
+      if (where == trees.length) where = 0;
+      partial = partial - heightToBytes(h);
+    }
+  }
+
+  // Interchanges two randomly selected subtrees (of same size and depth).
+
+  private static void oldGenSwapSubtrees() {
+    // Randomly pick:
+    //   * two tree indices
+    //   * A depth
+    //   * A path to that depth.
+    int index1 = rnd.nextInt(trees.length);
+    int index2 = rnd.nextInt(trees.length);
+    int depth = rnd.nextInt(treeHeight);
+    int path = rnd.nextInt();
+    TreeNode tn1 = trees[index1];
+    TreeNode tn2 = trees[index2];
+    for (int i = 0; i < depth; i++) {
+      if ((path & 1) == 0) {
+        tn1 = tn1.left;
+        tn2 = tn2.left;
+      } else {
+        tn1 = tn1.right;
+        tn2 = tn2.right;
+      }
+      path >>= 1;
+    }
+    TreeNode tmp;
+    if ((path & 1) == 0) {
+      tmp = tn1.left;
+      tn1.left = tn2.left;
+      tn2.left = tmp;
+    } else {
+      tmp = tn1.right;
+      tn1.right = tn2.right;
+      tn2.right = tmp;
+    }
+    actuallyMut += 2;
+  }
+
+  // Update "n" old-generation pointers.
+
+  private static void oldGenMut(long n) {
+    for (int i = 0; i < n/2; i++) {
+      oldGenSwapSubtrees();
+    }
+  }
+
+  // Does the amount of mutator work appropriate for n bytes of young-gen
+  // garbage allocation.
+
+  private static void doMutWork(long n) {
+    int sum = 0;
+    long limit = workUnits*n/10;
+    for (long k = 0; k < limit; k++) sum++;
+    // We don't want dead code elimination to eliminate the loop above.
+    mutatorSum = mutatorSum + sum;
+  }
+
+  // Allocate n bytes of young-gen garbage, in units of "nwords"
+  // words.
+
+  private static void doYoungGenAlloc(long n, int nwords) {
+    final int nbytes = nwords*BYTES_PER_WORD;
+    int allocated = 0;
+    while (allocated < n) {
+      aexport = new int[nwords];
+      /* System.err.println("Step"); */
+      allocated += nbytes;
+    }
+    youngBytes = youngBytes + allocated;
+  }
+
+  // Allocate "n" bytes of young-gen data; and do the
+  // corresponding amount of old-gen allocation and pointer
+  // mutation.
+
+  // oldGenAlloc may perform some mutations, so this code
+  // takes those mutations into account.
+
+  private static void doStep(long n) {
+    long mutations = actuallyMut;
+
+    doYoungGenAlloc(n, WORDS_DEAD);
+    doMutWork(n);
+    oldGenAlloc(n / promoteRate);
+    oldGenMut(Math.max(0L, (mutations + ptrMutRate) - actuallyMut));
+  }
+
+  public static void main(String[] args) {
+    if (args.length != 5) {
+      System.err.println(msg1);
+      System.err.println(msg2);
+      System.err.println(msg3);
+      System.err.println(msg4);
+      System.err.println(msg5);
+      System.err.println(msg6);
+      return;
+    }
+
+    size = Integer.parseInt(args[0]);
+    workUnits = Integer.parseInt(args[1]);
+    promoteRate = Integer.parseInt(args[2]);
+    ptrMutRate = Integer.parseInt(args[3]);
+    steps = Integer.parseInt(args[4]);
+
+    System.out.println(size + " megabytes of live storage");
+    System.out.println(workUnits + " work units per step");
+    System.out.println("promotion ratio is 1:" + promoteRate);
+    System.out.println("pointer mutation rate is " + ptrMutRate);
+    System.out.println(steps + " steps");
+
+    init();
+//  checkTrees();
+    youngBytes = 0;
+    nodes = 0;
+
+    System.err.println("Initialization complete...");
+
+    long start = System.currentTimeMillis();
+
+    for (int step = 0; step < steps; step++) {
+      doStep(MEG);
+    }
+
+    long end = System.currentTimeMillis();
+    float secs = ((float)(end-start))/1000.0F;
+
+//  checkTrees();
+
+    NumberFormat nf = NumberFormat.getInstance();
+    nf.setMaximumFractionDigits(1);
+    System.out.println("\nTook " + nf.format(secs) + " sec in steady state.");
+    nf.setMaximumFractionDigits(2);
+    System.out.println("Allocated " + steps + " Mb of young gen garbage"
+                       + " (= " + nf.format(((float)steps)/secs) +
+                       " Mb/sec)");
+    System.out.println("    (actually allocated " +
+                       nf.format(((float) youngBytes)/MEG) + " megabytes)");
+    float promoted = ((float)steps) / (float)promoteRate;
+    System.out.println("Promoted " + promoted +
+                       " Mb (= " + nf.format(promoted/secs) + " Mb/sec)");
+    System.out.println("    (actually promoted " +
+                       nf.format(((float) (nodes * BYTES_PER_NODE))/MEG) +
+                       " megabytes)");
+    if (ptrMutRate != 0) {
+      System.out.println("Mutated " + actuallyMut +
+                         " pointers (= " +
+                         nf.format(actuallyMut/secs) + " ptrs/sec)");
+
+    }
+    // This output serves mainly to discourage optimization.
+    System.out.println("Checksum = " + (mutatorSum + aexport.length));
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestMultiThreadStressRSet.java	Fri Apr 15 17:17:58 2016 +0200
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestMultiThreadStressRSet.java
+ * @key stress
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 2G
+ *
+ * @summary Stress G1 Remembered Set using multiple threads
+ * @library /test/lib /testlibrary
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc
+ *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ *   -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16
+ *
+ * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32
+ */
+public class TestMultiThreadStressRSet {
+
+    private static final Random RND = new Random(2015 * 2016);
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+    private static final int REF_SIZE = WB.getHeapOopSize();
+    private static final int REGION_SIZE = WB.g1RegionSize();
+
+    // How many regions to use for the storage
+    private static final int STORAGE_REGIONS = 20;
+
+    // Size a single obj in the storage
+    private static final int OBJ_SIZE = 1024;
+
+    // How many regions of young/old gen to use in the BUFFER
+    private static final int BUFFER_YOUNG_REGIONS = 60;
+    private static final int BUFFER_OLD_REGIONS = 40;
+
+    // Total number of objects in the storage.
+    private final int N;
+
+    // The storage of byte[]
+    private final List<Object> STORAGE;
+
+    // Where references to the Storage will be stored
+    private final List<Object[]> BUFFER;
+
+    // The length of a buffer element.
+    // RSet deals with "cards" (areas of 512 bytes), not with single refs
+    // So, to affect the RSet the BUFFER refs should be allocated in different
+    // memory cards.
+    private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE);
+
+    // Total number of objects in the young/old buffers
+    private final int YOUNG;
+    private final int OLD;
+
+    // To cause Remembered Sets change their coarse level the test uses a window
+    // within STORAGE. All the BUFFER elements refer to only STORAGE objects
+    // from the current window. The window is defined by a range.
+    // The first element has got the index: 'windowStart',
+    // the last one: 'windowStart + windowSize - 1'
+    // The window is shifting periodically.
+    private int windowStart;
+    private final int windowSize;
+
+    // Counter of created worker threads
+    private int counter = 0;
+
+    private volatile String errorMessage = null;
+    private volatile boolean isEnough = false;
+
+    public static void main(String args[]) {
+        if (args.length != 2) {
+            throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length);
+        }
+        long time = Long.parseLong(args[0]);
+        int threads = Integer.parseInt(args[1]);
+        new TestMultiThreadStressRSet().test(time * 1000, threads);
+    }
+
+    /**
+     * Initiates test parameters, fills out the STORAGE and BUFFER.
+     */
+    public TestMultiThreadStressRSet() {
+
+        N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1;
+        STORAGE = new ArrayList<>(N);
+        int bytes = OBJ_SIZE - 20;
+        for (int i = 0; i < N - 1; i++) {
+            STORAGE.add(new byte[bytes]);
+        }
+        STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous
+        windowStart = 0;
+        windowSize = REGION_SIZE / OBJ_SIZE;
+
+        BUFFER = new ArrayList<>();
+        int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN;
+        OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject;
+        YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject;
+        for (int i = 0; i < OLD + YOUNG; i++) {
+            BUFFER.add(new Object[BUF_ARR_LEN]);
+        }
+    }
+
+    /**
+     * Does the testing. Steps:
+     * <ul>
+     * <li> starts the Shifter thread
+     * <li> during the given time starts new Worker threads, keeping the number
+     * of live thread under limit.
+     * <li> stops the Shifter thread
+     * </ul>
+     *
+     * @param timeInMillis how long to stress
+     * @param maxThreads the maximum number of Worker thread working together.
+     */
+    public void test(long timeInMillis, int maxThreads) {
+        if (timeInMillis <= 0 || maxThreads <= 0) {
+            throw new IllegalArgumentException("TEST BUG: be positive!");
+        }
+        System.out.println("%% Time to work: " + timeInMillis / 1000 + "s");
+        System.out.println("%% Number of threads: " + maxThreads);
+        long finish = System.currentTimeMillis() + timeInMillis;
+        Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9));
+        shift.start();
+        for (int i = 0; i < maxThreads; i++) {
+            new Worker(this, 100).start();
+        }
+        try {
+            while (System.currentTimeMillis() < finish && errorMessage == null) {
+                Thread.sleep(100);
+            }
+        } catch (Throwable t) {
+            printAllStackTraces(System.err);
+            t.printStackTrace(System.err);
+            this.errorMessage = t.getMessage();
+        } finally {
+            isEnough = true;
+        }
+        System.out.println("%% Total work cycles: " + counter);
+        if (errorMessage != null) {
+            throw new RuntimeException(errorMessage);
+        }
+    }
+
+    /**
+     * Returns an element from from the BUFFER (an object array) to keep
+     * references to the storage.
+     *
+     * @return an Object[] from buffer.
+     */
+    private Object[] getFromBuffer() {
+        int index = counter % (OLD + YOUNG);
+        synchronized (BUFFER) {
+            if (index < OLD) {
+                if (counter % 100 == (counter / 100) % 100) {
+                    // need to generate garbage in the old gen to provoke mixed GC
+                    return replaceInBuffer(index);
+                } else {
+                    return BUFFER.get(index);
+                }
+            } else {
+                return replaceInBuffer(index);
+            }
+        }
+    }
+
+    private Object[] replaceInBuffer(int index) {
+        Object[] objs = new Object[BUF_ARR_LEN];
+        BUFFER.set(index, objs);
+        return objs;
+    }
+
+    /**
+     * Returns a random object from the current window within the storage.
+     * A storage element with index from windowStart to windowStart+windowSize.
+     *
+     * @return a random element from the current window within the storage.
+     */
+    private Object getRandomObject() {
+        int index = (windowStart + RND.nextInt(windowSize)) % N;
+        return STORAGE.get(index);
+    }
+
+    private static void printAllStackTraces(PrintStream ps) {
+        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+        for (Thread t : traces.keySet()) {
+            ps.println(t.toString() + " " + t.getState());
+            for (StackTraceElement traceElement : traces.get(t)) {
+                ps.println("\tat " + traceElement);
+            }
+        }
+    }
+
+    /**
+     * Thread to create a number of references from BUFFER to STORAGE.
+     */
+    private static class Worker extends Thread {
+
+        final TestMultiThreadStressRSet boss;
+        final int refs; // number of refs to OldGen
+
+        /**
+         * @param boss the tests
+         * @param refsToOldGen how many references to the OldGen to create
+         */
+        Worker(TestMultiThreadStressRSet boss, int refsToOldGen) {
+            this.boss = boss;
+            this.refs = refsToOldGen;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!boss.isEnough) {
+                    Object[] objs = boss.getFromBuffer();
+                    int step = objs.length / refs;
+                    for (int i = 0; i < refs; i += step) {
+                        objs[i] = boss.getRandomObject();
+                    }
+                    boss.counter++;
+                }
+            } catch (Throwable t) {
+                t.printStackTrace(System.out);
+                boss.errorMessage = t.getMessage();
+            }
+        }
+    }
+
+    /**
+     * Periodically shifts the current STORAGE window, removing references
+     * in BUFFER that refer to objects outside the window.
+     */
+    private static class Shifter extends Thread {
+
+        final TestMultiThreadStressRSet boss;
+        final int sleepTime;
+        final int shift;
+
+        Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) {
+            this.boss = boss;
+            this.sleepTime = sleepTime;
+            this.shift = shift;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!boss.isEnough) {
+                    Thread.sleep(sleepTime);
+                    boss.windowStart += shift;
+                    for (int i = 0; i < boss.OLD; i++) {
+                        Object[] objs = boss.BUFFER.get(i);
+                        for (int j = 0; j < objs.length; j++) {
+                            objs[j] = null;
+                        }
+                    }
+                    if (!WB.g1InConcurrentMark()) {
+                        System.out.println("%% start CMC");
+                        WB.g1StartConcMarkCycle();
+                    } else {
+                        System.out.println("%% CMC is already in progress");
+                    }
+                }
+            } catch (Throwable t) {
+                t.printStackTrace(System.out);
+                boss.errorMessage = t.getMessage();
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestStressIHOPMultiThread.java	Fri Apr 15 17:17:58 2016 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2016, 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 TestStressIHOPMultiThread
+ * @bug 8148397
+ * @key stress
+ * @summary Stress test for IHOP
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
+ *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
+ *              -Dthreads=2 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
+ *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
+ *              -Dthreads=3 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
+ *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
+ *              -Dthreads=5 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
+ *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
+ *              -Dthreads=10 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
+ *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
+ *              -Dthreads=17 TestStressIHOPMultiThread
+ */
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
+ * specified amount of memory. Tests work with enabled IHOP logging.
+ *
+ */
+public class TestStressIHOPMultiThread {
+
+    public final static List<Object> GARBAGE = new LinkedList<>();
+
+    private final long HEAP_SIZE;
+    // Amount of memory to be allocated before iterations start
+    private final long HEAP_PREALLOC_SIZE;
+    // Amount of memory to be allocated and freed during iterations
+    private final long HEAP_ALLOC_SIZE;
+    private final int CHUNK_SIZE = 100000;
+
+    private final int TIMEOUT;
+    private final int THREADS;
+    private final int HEAP_LOW_BOUND;
+    private final int HEAP_HIGH_BOUND;
+
+    private volatile boolean running = true;
+    private final List<AllocationThread> threads;
+
+    public static void main(String[] args) throws InterruptedException {
+        new TestStressIHOPMultiThread().start();
+
+    }
+
+    TestStressIHOPMultiThread() {
+
+        TIMEOUT = Integer.getInteger("timeout") * 60;
+        THREADS = Integer.getInteger("threads");
+        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
+        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
+        HEAP_SIZE = Runtime.getRuntime().maxMemory();
+
+        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
+        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;
+
+        threads = new ArrayList<>(THREADS);
+    }
+
+    public void start() throws InterruptedException {
+        fill();
+        createThreads();
+        waitForStress();
+        stressDone();
+        waitForFinish();
+    }
+
+    /**
+     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
+     */
+    private void fill() {
+        long allocated = 0;
+        while (allocated < HEAP_PREALLOC_SIZE) {
+            GARBAGE.add(new byte[CHUNK_SIZE]);
+            allocated += CHUNK_SIZE;
+        }
+    }
+
+    /**
+     * Creates a number of threads which will fill and free amount of memory.
+     */
+    private void createThreads() {
+        for (int i = 0; i < THREADS; ++i) {
+            System.out.println("Create thread " + i);
+            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
+            // Put reference to thread garbage into common garbage for avoiding possible optimization.
+            GARBAGE.add(thread.getList());
+            threads.add(thread);
+        }
+        threads.forEach(t -> t.start());
+    }
+
+    /**
+     * Wait each thread for finishing
+     */
+    private void waitForFinish() {
+        threads.forEach(thread -> {
+            thread.silentJoin();
+        });
+    }
+
+    private boolean isRunning() {
+        return running;
+    }
+
+    private void stressDone() {
+        running = false;
+    }
+
+    private void waitForStress() throws InterruptedException {
+        Thread.sleep(TIMEOUT * 1000);
+    }
+
+    private class AllocationThread extends Thread {
+
+        private final List<Object> garbage;
+
+        private final long amountOfGarbage;
+        private final int threadId;
+
+        public AllocationThread(int id, long amount) {
+            super("Thread " + id);
+            threadId = id;
+            amountOfGarbage = amount;
+            garbage = new LinkedList<>();
+        }
+
+        /**
+         * Returns list of garbage.
+         * @return List with thread garbage.
+         */
+        public List<Object> getList(){
+            return garbage;
+        }
+
+        @Override
+        public void run() {
+            System.out.println("Start the thread " + threadId);
+            while (TestStressIHOPMultiThread.this.isRunning()) {
+                allocate(amountOfGarbage);
+                free();
+            }
+        }
+
+        private void silentJoin() {
+            System.out.println("Join the thread " + threadId);
+            try {
+                join();
+            } catch (InterruptedException ie) {
+                throw new RuntimeException(ie);
+            }
+        }
+
+        /**
+         * Allocates thread local garbage
+         */
+        private void allocate(long amount) {
+            long allocated = 0;
+            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
+                garbage.add(new byte[CHUNK_SIZE]);
+                allocated += CHUNK_SIZE;
+            }
+        }
+
+        /**
+         * Frees thread local garbage
+         */
+        private void free() {
+            garbage.clear();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestStressRSetCoarsening.java	Fri Apr 15 17:17:58 2016 +0200
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.util.concurrent.TimeoutException;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestStressRSetCoarsening.java
+ * @key stress
+ * @bug 8146984 8147087
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 3G
+ *
+ * @summary Stress G1 Remembered Set by creating a lot of cross region links
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  1  0 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=8m TestStressRSetCoarsening  1 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=32m TestStressRSetCoarsening 42 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  2 0 300
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 500 0  1800
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 10  10 1800
+ */
+
+/**
+ * What the test does.
+ * Preparation stage:
+ *   Fill out ~90% of the heap with objects, each object is an object array.
+ *   If we want to allocate K objects per region, we calculate N to meet:
+ *      sizeOf(Object[N]) ~= regionSize / K
+ * Stress stage:
+ *   No more allocation, so no more GC.
+ *   We will perform a number of  iterations. On each iteration i,
+ *   for each pair of regions Rx and Ry we will set c[i] references
+ *   from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
+ *   concurrent mark cycle will be initiated (to recalculate remembered sets).
+ *   As the result RSet will be growing up and down, up and down many times.
+ *
+ * The test expects: no crash and no timeouts.
+ *
+ * Test Parameters:
+ *   args[0] - number of objects per Heap Region (1 - means humongous)
+ *   args[1] - number of regions to refresh to provoke GC at the end of cycle.
+ *             (0 - means no GC, i.e. no reading from RSet)
+ *   args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
+ */
+public class TestStressRSetCoarsening {
+
+    public static void main(String... args) throws InterruptedException {
+        if (args.length != 3) {
+            throw new IllegalArgumentException("Wrong number of arguments " + args.length);
+        }
+        int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
+        int regsToRefresh = Integer.parseInt(args[1]);  // 0 means no regions to refresh at the end of cycle
+        int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
+        new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
+    }
+
+    private static final long KB = 1024;
+    private static final long MB = 1024 * KB;
+
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    public final Object[][] storage;
+
+    /**
+     * Number of objects per region. This is a test parameter.
+     */
+    public final int K;
+
+    /**
+     * Length of object array: sizeOf(Object[N]) ~= regionSize / K
+     * N will be calculated as function of K.
+     */
+    public final int N;
+
+    /**
+     * How many regions involved into testing.
+     * Will be calculated as heapFractionToAllocate * freeRegionCount.
+     */
+    public final int regionCount;
+
+    /**
+     * How much heap to use.
+     */
+    public final float heapFractionToAllocate = 0.9f;
+
+    /**
+     * How many regions to be refreshed at the end of cycle.
+     * This is a test parameter.
+     */
+    public final int regsToRefresh;
+
+    /**
+     * Initial time.
+     */
+    public final long start;
+
+    /**
+     * Time when the test should stop working.
+     */
+    public final long finishAt;
+
+    /**
+     * Does pre-calculation and allocate necessary objects.
+     *
+     * @param objPerRegions how many objects per G1 heap region
+     */
+    TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
+        this.K = objPerRegions;
+        this.regsToRefresh = regsToRefresh;
+        this.start = System.currentTimeMillis();
+        this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
+
+        long regionSize = WB.g1RegionSize();
+
+        // How many free regions
+        Runtime rt = Runtime.getRuntime();
+        long used = rt.totalMemory() - rt.freeMemory();
+        long totalFree = rt.maxMemory() - used;
+        regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
+        long toAllocate = regionCount * regionSize;
+        System.out.println("%% Test parameters");
+        System.out.println("%%   Objects per region              : " + K);
+        System.out.println("%%   Heap fraction to allocate       : " + (int) (heapFractionToAllocate * 100) + "%");
+        System.out.println("%%   Regions to refresh to provoke GC: " + regsToRefresh);
+
+        System.out.println("%% Memory");
+        System.out.println("%%   used          :        " + used / MB + "M");
+        System.out.println("%%   available     :        " + totalFree / MB + "M");
+        System.out.println("%%   to allocate   :        " + toAllocate / MB + "M");
+        System.out.println("%%     (in regs)   :        " + regionCount);
+        System.out.println("%%   G1 Region Size:        " + regionSize / MB + "M");
+
+        int refSize = WB.getHeapOopSize();
+
+        // Calculate N:    K*sizeOf(Object[N]) ~= regionSize
+        //                 sizeOf(Object[N]) ~=  (N+4)*refSize
+        // ==>
+        //                 N = regionSize / K / refSize - 4;
+        int n = (int) ((regionSize / K) / refSize) - 5;  // best guess
+        long objSize = WB.getObjectSize(new Object[n]);
+        while (K*objSize > regionSize) {   // adjust to avoid OOME
+            n = n - 1;
+            objSize = WB.getObjectSize(new Object[n]);
+        }
+        N = n;
+
+        /*
+         *   --------------
+         *   region0   storage[0]        = new Object[N]
+         *             ...
+         *             storage[K-1]      = new Object[N]
+         *   ---------------
+         *   region1   storage[K]        = new Object[N]
+         *             ...
+         *             storage[2*K - 1]  = new Object[N]
+         *   --------------
+         *   ...
+         *   --------------
+         *   regionX   storage[X*K]         = new Object[N]
+         *             ...
+         *             storage[(X+1)*K -1]  = new Object[N]
+         *    where X = HeapFraction * TotalRegions
+         *   -------------
+         */
+        System.out.println("%% Objects");
+        System.out.println("%%   N (array length)      : " + N);
+        System.out.println("%%   K (objects in regions): " + K);
+        System.out.println("%%   Object size           : " + objSize +
+                "  (sizeOf(new Object[" + N + "])");
+        System.out.println("%%   Reference size        : " + refSize);
+
+        storage = new Object[regionCount * K][];
+        for (int i = 0; i < storage.length; i++) {
+            storage[i] = new Object[N];
+        }
+    }
+
+    public void go() throws InterruptedException {
+        // threshold for sparce -> fine
+        final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
+
+        // threshold for fine -> coarse
+        final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
+
+        // regToRegRefCounts - array of reference counts from region to region
+        // at the the end of iteration.
+        // The number of test iterations is array length - 1.
+        // If c[i] > c[i-1] then during the iteration i more references will
+        // be created.
+        // If c[i] < c[i-1] then some referenes will be cleaned.
+        int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
+            COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
+
+        // For progress tracking
+        int[] progress = new int[regToRegRefCounts.length];
+        progress[0] = 0;
+        for (int i = 1; i < regToRegRefCounts.length; i++) {
+            progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
+        }
+        try {
+            for (int i = 1; i < regToRegRefCounts.length; i++) {
+                int pre = regToRegRefCounts[i - 1];
+                int cur = regToRegRefCounts[i];
+                float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
+
+                System.out.println("%% step " + i
+                        + " out of " + (regToRegRefCounts.length - 1)
+                        + " (~" + (int) (100 * prog) + "% done)");
+                System.out.println("%%      " + pre + "  --> " + cur);
+                for (int to = 0; to < regionCount; to++) {
+                    // Select a celebrity object that we will install references to.
+                    // The celebrity will be referred from all other regions.
+                    // If the number of references after should be less than they
+                    // were before, select NULL.
+                    Object celebrity = cur > pre ? storage[to * K] : null;
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+
+                        int step = cur > pre ? +1 : -1;
+                        for (int rn = pre; rn != cur; rn += step) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
+                            if (System.currentTimeMillis() > finishAt) {
+                                throw new TimeoutException();
+                            }
+                        }
+                    }
+                }
+                if (pre > cur) {
+                    // Number of references went down.
+                    // Need to provoke recalculation of RSet.
+                    WB.g1StartConcMarkCycle();
+                    while (WB.g1InConcurrentMark()) {
+                        Thread.sleep(1);
+                    }
+                }
+
+                // To force the use of rememebered set entries we need to provoke a GC.
+                // To induce some fragmentation, and some mixed GCs, we need
+                // to make a few objects unreachable.
+                for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
+                    int to = toClean % regionCount;
+                    // Need to remove all references from all regions to the region 'to'
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+                        for (int rn = 0; rn <= cur; rn++) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = null;
+                        }
+                    }
+                    // 'Refresh' storage elements for the region 'to'
+                    // After that loop all 'old' objects in the region 'to'
+                    // should become unreachable.
+                    for (int k = 0; k < K; k++) {
+                        storage[(to * K + k) % storage.length] = new Object[N];
+                    }
+                }
+            }
+        } catch (TimeoutException e) {
+            System.out.println("%% TIMEOUT!!!");
+        }
+        long now = System.currentTimeMillis();
+        System.out.println("%% Summary");
+        System.out.println("%%   Time spent          : " + ((now - start) / 1000) + " seconds");
+        System.out.println("%%   Free memory left    : " + Runtime.getRuntime().freeMemory() / KB + "K");
+        System.out.println("%% Test passed");
+    }
+
+    /**
+     * Returns X index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return X index in the range: [0 ... N-1]
+     */
+    private int getX(int to, int from, int rn) {
+        return (rn * regionCount + to) % N;
+    }
+
+    /**
+     * Returns Y index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return Y index in the range: [0 ... K*regionCount -1]
+     */
+    private int getY(int to, int from, int rn) {
+        return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
+    }
+}
+
--- a/test/stress/gc/TestGCOld.java	Thu Apr 14 19:55:39 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,417 +0,0 @@
-/*
-* Copyright (c) 2015, 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 TestGCOld
- * @key gc
- * @key stress
- * @requires vm.gc=="null"
- * @summary Stress the GC by trying to make old objects more likely to be garbage than young objects.
- * @run main/othervm -Xmx384M -XX:+UseSerialGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseParallelGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseParallelGC -XX:-UseParallelOldGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseConcMarkSweepGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseG1GC TestGCOld 50 1 20 10 10000
- */
-
-import java.text.*;
-import java.util.Random;
-
-class TreeNode {
-    public TreeNode left, right;
-    public int val;                // will always be the height of the tree
-}
-
-
-/* Args:
-   live-data-size: in megabytes (approximate, will be rounded down).
-   work: units of mutator non-allocation work per byte allocated,
-     (in unspecified units.  This will affect the promotion rate
-      printed at the end of the run: more mutator work per step implies
-      fewer steps per second implies fewer bytes promoted per second.)
-   short/long ratio: ratio of short-lived bytes allocated to long-lived
-      bytes allocated.
-   pointer mutation rate: number of pointer mutations per step.
-   steps: number of steps to do.
-*/
-
-public class TestGCOld {
-
-  // Command-line parameters.
-
-  private static int size, workUnits, promoteRate, ptrMutRate, steps;
-
-  // Constants.
-
-  private static final int MEG = 1000000;
-  private static final int INSIGNIFICANT = 999; // this many bytes don't matter
-  private static final int BYTES_PER_WORD = 4;
-  private static final int BYTES_PER_NODE = 20; // bytes per TreeNode
-  private static final int WORDS_DEAD = 100;    // size of young garbage object
-
-  private final static int treeHeight = 14;
-  private final static long treeSize = heightToBytes(treeHeight);
-
-  private static final String msg1
-    = "Usage: java TestGCOld <size> <work> <ratio> <mutation> <steps>";
-  private static final String msg2
-    = "  where <size> is the live storage in megabytes";
-  private static final String msg3
-    = "        <work> is the mutator work per step (arbitrary units)";
-  private static final String msg4
-    = "        <ratio> is the ratio of short-lived to long-lived allocation";
-  private static final String msg5
-    = "        <mutation> is the mutations per step";
-  private static final String msg6
-    = "        <steps> is the number of steps";
-
-  // Counters (and global variables that discourage optimization)
-
-  private static long youngBytes = 0;    // total young bytes allocated
-  private static long nodes = 0;         // total tree nodes allocated
-  private static long actuallyMut = 0;   // pointer mutations in old trees
-  private static long mutatorSum = 0;    // checksum to discourage optimization
-  public static int[] aexport;           // exported array to discourage opt
-
-  // Global variables.
-
-  private static TreeNode[] trees;
-  private static int where = 0;               // roving index into trees
-  private static Random rnd = new Random();
-
-  // Returns the height of the given tree.
-
-  private static int height (TreeNode t) {
-    if (t == null) {
-      return 0;
-    }
-    else {
-      return 1 + Math.max (height (t.left), height (t.right));
-    }
-  }
-
-  // Returns the length of the shortest path in the given tree.
-
-  private static int shortestPath (TreeNode t) {
-    if (t == null) {
-      return 0;
-    }
-    else {
-      return 1 + Math.min (shortestPath (t.left), shortestPath (t.right));
-    }
-  }
-
-  // Returns the number of nodes in a balanced tree of the given height.
-
-  private static long heightToNodes (int h) {
-    if (h == 0) {
-      return 0;
-    }
-    else {
-      long n = 1;
-      while (h > 1) {
-        n = n + n;
-        h = h - 1;
-      }
-      return n + n - 1;
-    }
-  }
-
-  // Returns the number of bytes in a balanced tree of the given height.
-
-  private static long heightToBytes (int h) {
-    return BYTES_PER_NODE * heightToNodes (h);
-  }
-
-  // Returns the height of the largest balanced tree
-  // that has no more than the given number of nodes.
-
-  private static int nodesToHeight (long nodes) {
-    int h = 1;
-    long n = 1;
-    while (n + n - 1 <= nodes) {
-      n = n + n;
-      h = h + 1;
-    }
-    return h - 1;
-  }
-
-  // Returns the height of the largest balanced tree
-  // that occupies no more than the given number of bytes.
-
-  private static int bytesToHeight (long bytes) {
-    return nodesToHeight (bytes / BYTES_PER_NODE);
-  }
-
-  // Returns a newly allocated balanced binary tree of height h.
-
-  private static TreeNode makeTree(int h) {
-    if (h == 0) return null;
-    else {
-      TreeNode res = new TreeNode();
-      nodes++;
-      res.left = makeTree(h-1);
-      res.right = makeTree(h-1);
-      res.val = h;
-      return res;
-    }
-  }
-
-  // Allocates approximately size megabytes of trees and stores
-  // them into a global array.
-
-  private static void init() {
-    int ntrees = (int) ((size * MEG) / treeSize);
-    trees = new TreeNode[ntrees];
-
-    System.err.println("Allocating " + ntrees + " trees.");
-    System.err.println("  (" + (ntrees * treeSize) + " bytes)");
-    for (int i = 0; i < ntrees; i++) {
-      trees[i] = makeTree(treeHeight);
-      // doYoungGenAlloc(promoteRate*ntrees*treeSize, WORDS_DEAD);
-    }
-    System.err.println("  (" + nodes + " nodes)");
-
-    /* Allow any in-progress GC to catch up... */
-    // try { Thread.sleep(20000); } catch (InterruptedException x) {}
-  }
-
-  // Confirms that all trees are balanced and have the correct height.
-
-  private static void checkTrees() {
-    int ntrees = trees.length;
-    for (int i = 0; i < ntrees; i++) {
-      TreeNode t = trees[i];
-      int h1 = height(t);
-      int h2 = shortestPath(t);
-      if ((h1 != treeHeight) || (h2 != treeHeight)) {
-        System.err.println("*****BUG: " + h1 + " " + h2);
-      }
-    }
-  }
-
-  // Called only by replaceTree (below) and by itself.
-
-  private static void replaceTreeWork(TreeNode full, TreeNode partial, boolean dir) {
-    boolean canGoLeft = full.left != null && full.left.val > partial.val;
-    boolean canGoRight = full.right != null && full.right.val > partial.val;
-    if (canGoLeft && canGoRight) {
-      if (dir)
-        replaceTreeWork(full.left, partial, !dir);
-      else
-        replaceTreeWork(full.right, partial, !dir);
-    } else if (!canGoLeft && !canGoRight) {
-      if (dir)
-        full.left = partial;
-      else
-        full.right = partial;
-    } else if (!canGoLeft) {
-      full.left = partial;
-    } else {
-      full.right = partial;
-    }
-  }
-
-  // Given a balanced tree full and a smaller balanced tree partial,
-  // replaces an appropriate subtree of full by partial, taking care
-  // to preserve the shape of the full tree.
-
-  private static void replaceTree(TreeNode full, TreeNode partial) {
-    boolean dir = (partial.val % 2) == 0;
-    actuallyMut++;
-    replaceTreeWork(full, partial, dir);
-  }
-
-  // Allocates approximately n bytes of long-lived storage,
-  // replacing oldest existing long-lived storage.
-
-  private static void oldGenAlloc(long n) {
-    int full = (int) (n / treeSize);
-    long partial = n % treeSize;
-    // System.out.println("In oldGenAlloc, doing " + full + " full trees "
-    // + "and one partial tree of size " + partial);
-    for (int i = 0; i < full; i++) {
-      trees[where++] = makeTree(treeHeight);
-      if (where == trees.length) where = 0;
-    }
-    while (partial > INSIGNIFICANT) {
-      int h = bytesToHeight(partial);
-      TreeNode newTree = makeTree(h);
-      replaceTree(trees[where++], newTree);
-      if (where == trees.length) where = 0;
-      partial = partial - heightToBytes(h);
-    }
-  }
-
-  // Interchanges two randomly selected subtrees (of same size and depth).
-
-  private static void oldGenSwapSubtrees() {
-    // Randomly pick:
-    //   * two tree indices
-    //   * A depth
-    //   * A path to that depth.
-    int index1 = rnd.nextInt(trees.length);
-    int index2 = rnd.nextInt(trees.length);
-    int depth = rnd.nextInt(treeHeight);
-    int path = rnd.nextInt();
-    TreeNode tn1 = trees[index1];
-    TreeNode tn2 = trees[index2];
-    for (int i = 0; i < depth; i++) {
-      if ((path & 1) == 0) {
-        tn1 = tn1.left;
-        tn2 = tn2.left;
-      } else {
-        tn1 = tn1.right;
-        tn2 = tn2.right;
-      }
-      path >>= 1;
-    }
-    TreeNode tmp;
-    if ((path & 1) == 0) {
-      tmp = tn1.left;
-      tn1.left = tn2.left;
-      tn2.left = tmp;
-    } else {
-      tmp = tn1.right;
-      tn1.right = tn2.right;
-      tn2.right = tmp;
-    }
-    actuallyMut += 2;
-  }
-
-  // Update "n" old-generation pointers.
-
-  private static void oldGenMut(long n) {
-    for (int i = 0; i < n/2; i++) {
-      oldGenSwapSubtrees();
-    }
-  }
-
-  // Does the amount of mutator work appropriate for n bytes of young-gen
-  // garbage allocation.
-
-  private static void doMutWork(long n) {
-    int sum = 0;
-    long limit = workUnits*n/10;
-    for (long k = 0; k < limit; k++) sum++;
-    // We don't want dead code elimination to eliminate the loop above.
-    mutatorSum = mutatorSum + sum;
-  }
-
-  // Allocate n bytes of young-gen garbage, in units of "nwords"
-  // words.
-
-  private static void doYoungGenAlloc(long n, int nwords) {
-    final int nbytes = nwords*BYTES_PER_WORD;
-    int allocated = 0;
-    while (allocated < n) {
-      aexport = new int[nwords];
-      /* System.err.println("Step"); */
-      allocated += nbytes;
-    }
-    youngBytes = youngBytes + allocated;
-  }
-
-  // Allocate "n" bytes of young-gen data; and do the
-  // corresponding amount of old-gen allocation and pointer
-  // mutation.
-
-  // oldGenAlloc may perform some mutations, so this code
-  // takes those mutations into account.
-
-  private static void doStep(long n) {
-    long mutations = actuallyMut;
-
-    doYoungGenAlloc(n, WORDS_DEAD);
-    doMutWork(n);
-    oldGenAlloc(n / promoteRate);
-    oldGenMut(Math.max(0L, (mutations + ptrMutRate) - actuallyMut));
-  }
-
-  public static void main(String[] args) {
-    if (args.length != 5) {
-      System.err.println(msg1);
-      System.err.println(msg2);
-      System.err.println(msg3);
-      System.err.println(msg4);
-      System.err.println(msg5);
-      System.err.println(msg6);
-      return;
-    }
-
-    size = Integer.parseInt(args[0]);
-    workUnits = Integer.parseInt(args[1]);
-    promoteRate = Integer.parseInt(args[2]);
-    ptrMutRate = Integer.parseInt(args[3]);
-    steps = Integer.parseInt(args[4]);
-
-    System.out.println(size + " megabytes of live storage");
-    System.out.println(workUnits + " work units per step");
-    System.out.println("promotion ratio is 1:" + promoteRate);
-    System.out.println("pointer mutation rate is " + ptrMutRate);
-    System.out.println(steps + " steps");
-
-    init();
-//  checkTrees();
-    youngBytes = 0;
-    nodes = 0;
-
-    System.err.println("Initialization complete...");
-
-    long start = System.currentTimeMillis();
-
-    for (int step = 0; step < steps; step++) {
-      doStep(MEG);
-    }
-
-    long end = System.currentTimeMillis();
-    float secs = ((float)(end-start))/1000.0F;
-
-//  checkTrees();
-
-    NumberFormat nf = NumberFormat.getInstance();
-    nf.setMaximumFractionDigits(1);
-    System.out.println("\nTook " + nf.format(secs) + " sec in steady state.");
-    nf.setMaximumFractionDigits(2);
-    System.out.println("Allocated " + steps + " Mb of young gen garbage"
-                       + " (= " + nf.format(((float)steps)/secs) +
-                       " Mb/sec)");
-    System.out.println("    (actually allocated " +
-                       nf.format(((float) youngBytes)/MEG) + " megabytes)");
-    float promoted = ((float)steps) / (float)promoteRate;
-    System.out.println("Promoted " + promoted +
-                       " Mb (= " + nf.format(promoted/secs) + " Mb/sec)");
-    System.out.println("    (actually promoted " +
-                       nf.format(((float) (nodes * BYTES_PER_NODE))/MEG) +
-                       " megabytes)");
-    if (ptrMutRate != 0) {
-      System.out.println("Mutated " + actuallyMut +
-                         " pointers (= " +
-                         nf.format(actuallyMut/secs) + " ptrs/sec)");
-
-    }
-    // This output serves mainly to discourage optimization.
-    System.out.println("Checksum = " + (mutatorSum + aexport.length));
-
-  }
-}
--- a/test/stress/gc/TestMultiThreadStressRSet.java	Thu Apr 14 19:55:39 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,305 +0,0 @@
-/*
- * Copyright (c) 2016, 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.
- */
-
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import sun.hotspot.WhiteBox;
-
-/*
- * @test TestMultiThreadStressRSet.java
- * @key stress
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @requires os.maxMemory > 2G
- *
- * @summary Stress G1 Remembered Set using multiple threads
- * @library /test/lib /testlibrary
- * @build sun.hotspot.WhiteBox
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc
- *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4
- *
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
- *   -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16
- *
- * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
- *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32
- */
-public class TestMultiThreadStressRSet {
-
-    private static final Random RND = new Random(2015 * 2016);
-    private static final WhiteBox WB = WhiteBox.getWhiteBox();
-    private static final int REF_SIZE = WB.getHeapOopSize();
-    private static final int REGION_SIZE = WB.g1RegionSize();
-
-    // How many regions to use for the storage
-    private static final int STORAGE_REGIONS = 20;
-
-    // Size a single obj in the storage
-    private static final int OBJ_SIZE = 1024;
-
-    // How many regions of young/old gen to use in the BUFFER
-    private static final int BUFFER_YOUNG_REGIONS = 60;
-    private static final int BUFFER_OLD_REGIONS = 40;
-
-    // Total number of objects in the storage.
-    private final int N;
-
-    // The storage of byte[]
-    private final List<Object> STORAGE;
-
-    // Where references to the Storage will be stored
-    private final List<Object[]> BUFFER;
-
-    // The length of a buffer element.
-    // RSet deals with "cards" (areas of 512 bytes), not with single refs
-    // So, to affect the RSet the BUFFER refs should be allocated in different
-    // memory cards.
-    private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE);
-
-    // Total number of objects in the young/old buffers
-    private final int YOUNG;
-    private final int OLD;
-
-    // To cause Remembered Sets change their coarse level the test uses a window
-    // within STORAGE. All the BUFFER elements refer to only STORAGE objects
-    // from the current window. The window is defined by a range.
-    // The first element has got the index: 'windowStart',
-    // the last one: 'windowStart + windowSize - 1'
-    // The window is shifting periodically.
-    private int windowStart;
-    private final int windowSize;
-
-    // Counter of created worker threads
-    private int counter = 0;
-
-    private volatile String errorMessage = null;
-    private volatile boolean isEnough = false;
-
-    public static void main(String args[]) {
-        if (args.length != 2) {
-            throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length);
-        }
-        long time = Long.parseLong(args[0]);
-        int threads = Integer.parseInt(args[1]);
-        new TestMultiThreadStressRSet().test(time * 1000, threads);
-    }
-
-    /**
-     * Initiates test parameters, fills out the STORAGE and BUFFER.
-     */
-    public TestMultiThreadStressRSet() {
-
-        N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1;
-        STORAGE = new ArrayList<>(N);
-        int bytes = OBJ_SIZE - 20;
-        for (int i = 0; i < N - 1; i++) {
-            STORAGE.add(new byte[bytes]);
-        }
-        STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous
-        windowStart = 0;
-        windowSize = REGION_SIZE / OBJ_SIZE;
-
-        BUFFER = new ArrayList<>();
-        int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN;
-        OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject;
-        YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject;
-        for (int i = 0; i < OLD + YOUNG; i++) {
-            BUFFER.add(new Object[BUF_ARR_LEN]);
-        }
-    }
-
-    /**
-     * Does the testing. Steps:
-     * <ul>
-     * <li> starts the Shifter thread
-     * <li> during the given time starts new Worker threads, keeping the number
-     * of live thread under limit.
-     * <li> stops the Shifter thread
-     * </ul>
-     *
-     * @param timeInMillis how long to stress
-     * @param maxThreads the maximum number of Worker thread working together.
-     */
-    public void test(long timeInMillis, int maxThreads) {
-        if (timeInMillis <= 0 || maxThreads <= 0) {
-            throw new IllegalArgumentException("TEST BUG: be positive!");
-        }
-        System.out.println("%% Time to work: " + timeInMillis / 1000 + "s");
-        System.out.println("%% Number of threads: " + maxThreads);
-        long finish = System.currentTimeMillis() + timeInMillis;
-        Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9));
-        shift.start();
-        for (int i = 0; i < maxThreads; i++) {
-            new Worker(this, 100).start();
-        }
-        try {
-            while (System.currentTimeMillis() < finish && errorMessage == null) {
-                Thread.sleep(100);
-            }
-        } catch (Throwable t) {
-            printAllStackTraces(System.err);
-            t.printStackTrace(System.err);
-            this.errorMessage = t.getMessage();
-        } finally {
-            isEnough = true;
-        }
-        System.out.println("%% Total work cycles: " + counter);
-        if (errorMessage != null) {
-            throw new RuntimeException(errorMessage);
-        }
-    }
-
-    /**
-     * Returns an element from from the BUFFER (an object array) to keep
-     * references to the storage.
-     *
-     * @return an Object[] from buffer.
-     */
-    private Object[] getFromBuffer() {
-        int index = counter % (OLD + YOUNG);
-        synchronized (BUFFER) {
-            if (index < OLD) {
-                if (counter % 100 == (counter / 100) % 100) {
-                    // need to generate garbage in the old gen to provoke mixed GC
-                    return replaceInBuffer(index);
-                } else {
-                    return BUFFER.get(index);
-                }
-            } else {
-                return replaceInBuffer(index);
-            }
-        }
-    }
-
-    private Object[] replaceInBuffer(int index) {
-        Object[] objs = new Object[BUF_ARR_LEN];
-        BUFFER.set(index, objs);
-        return objs;
-    }
-
-    /**
-     * Returns a random object from the current window within the storage.
-     * A storage element with index from windowStart to windowStart+windowSize.
-     *
-     * @return a random element from the current window within the storage.
-     */
-    private Object getRandomObject() {
-        int index = (windowStart + RND.nextInt(windowSize)) % N;
-        return STORAGE.get(index);
-    }
-
-    private static void printAllStackTraces(PrintStream ps) {
-        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
-        for (Thread t : traces.keySet()) {
-            ps.println(t.toString() + " " + t.getState());
-            for (StackTraceElement traceElement : traces.get(t)) {
-                ps.println("\tat " + traceElement);
-            }
-        }
-    }
-
-    /**
-     * Thread to create a number of references from BUFFER to STORAGE.
-     */
-    private static class Worker extends Thread {
-
-        final TestMultiThreadStressRSet boss;
-        final int refs; // number of refs to OldGen
-
-        /**
-         * @param boss the tests
-         * @param refsToOldGen how many references to the OldGen to create
-         */
-        Worker(TestMultiThreadStressRSet boss, int refsToOldGen) {
-            this.boss = boss;
-            this.refs = refsToOldGen;
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!boss.isEnough) {
-                    Object[] objs = boss.getFromBuffer();
-                    int step = objs.length / refs;
-                    for (int i = 0; i < refs; i += step) {
-                        objs[i] = boss.getRandomObject();
-                    }
-                    boss.counter++;
-                }
-            } catch (Throwable t) {
-                t.printStackTrace(System.out);
-                boss.errorMessage = t.getMessage();
-            }
-        }
-    }
-
-    /**
-     * Periodically shifts the current STORAGE window, removing references
-     * in BUFFER that refer to objects outside the window.
-     */
-    private static class Shifter extends Thread {
-
-        final TestMultiThreadStressRSet boss;
-        final int sleepTime;
-        final int shift;
-
-        Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) {
-            this.boss = boss;
-            this.sleepTime = sleepTime;
-            this.shift = shift;
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!boss.isEnough) {
-                    Thread.sleep(sleepTime);
-                    boss.windowStart += shift;
-                    for (int i = 0; i < boss.OLD; i++) {
-                        Object[] objs = boss.BUFFER.get(i);
-                        for (int j = 0; j < objs.length; j++) {
-                            objs[j] = null;
-                        }
-                    }
-                    if (!WB.g1InConcurrentMark()) {
-                        System.out.println("%% start CMC");
-                        WB.g1StartConcMarkCycle();
-                    } else {
-                        System.out.println("%% CMC is already in progress");
-                    }
-                }
-            } catch (Throwable t) {
-                t.printStackTrace(System.out);
-                boss.errorMessage = t.getMessage();
-            }
-        }
-    }
-}
-
--- a/test/stress/gc/TestStressIHOPMultiThread.java	Thu Apr 14 19:55:39 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +0,0 @@
-/*
- * Copyright (c) 2016, 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 TestStressIHOPMultiThread
- * @bug 8148397
- * @key stress
- * @summary Stress test for IHOP
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
- *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
- *              -Dthreads=2 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
- *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
- *              -Dthreads=3 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
- *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
- *              -Dthreads=5 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
- *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
- *              -Dthreads=10 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
- *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
- *              -Dthreads=17 TestStressIHOPMultiThread
- */
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
- * specified amount of memory. Tests work with enabled IHOP logging.
- *
- */
-public class TestStressIHOPMultiThread {
-
-    public final static List<Object> GARBAGE = new LinkedList<>();
-
-    private final long HEAP_SIZE;
-    // Amount of memory to be allocated before iterations start
-    private final long HEAP_PREALLOC_SIZE;
-    // Amount of memory to be allocated and freed during iterations
-    private final long HEAP_ALLOC_SIZE;
-    private final int CHUNK_SIZE = 100000;
-
-    private final int TIMEOUT;
-    private final int THREADS;
-    private final int HEAP_LOW_BOUND;
-    private final int HEAP_HIGH_BOUND;
-
-    private volatile boolean running = true;
-    private final List<AllocationThread> threads;
-
-    public static void main(String[] args) throws InterruptedException {
-        new TestStressIHOPMultiThread().start();
-
-    }
-
-    TestStressIHOPMultiThread() {
-
-        TIMEOUT = Integer.getInteger("timeout") * 60;
-        THREADS = Integer.getInteger("threads");
-        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
-        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
-        HEAP_SIZE = Runtime.getRuntime().maxMemory();
-
-        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
-        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;
-
-        threads = new ArrayList<>(THREADS);
-    }
-
-    public void start() throws InterruptedException {
-        fill();
-        createThreads();
-        waitForStress();
-        stressDone();
-        waitForFinish();
-    }
-
-    /**
-     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
-     */
-    private void fill() {
-        long allocated = 0;
-        while (allocated < HEAP_PREALLOC_SIZE) {
-            GARBAGE.add(new byte[CHUNK_SIZE]);
-            allocated += CHUNK_SIZE;
-        }
-    }
-
-    /**
-     * Creates a number of threads which will fill and free amount of memory.
-     */
-    private void createThreads() {
-        for (int i = 0; i < THREADS; ++i) {
-            System.out.println("Create thread " + i);
-            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
-            // Put reference to thread garbage into common garbage for avoiding possible optimization.
-            GARBAGE.add(thread.getList());
-            threads.add(thread);
-        }
-        threads.forEach(t -> t.start());
-    }
-
-    /**
-     * Wait each thread for finishing
-     */
-    private void waitForFinish() {
-        threads.forEach(thread -> {
-            thread.silentJoin();
-        });
-    }
-
-    private boolean isRunning() {
-        return running;
-    }
-
-    private void stressDone() {
-        running = false;
-    }
-
-    private void waitForStress() throws InterruptedException {
-        Thread.sleep(TIMEOUT * 1000);
-    }
-
-    private class AllocationThread extends Thread {
-
-        private final List<Object> garbage;
-
-        private final long amountOfGarbage;
-        private final int threadId;
-
-        public AllocationThread(int id, long amount) {
-            super("Thread " + id);
-            threadId = id;
-            amountOfGarbage = amount;
-            garbage = new LinkedList<>();
-        }
-
-        /**
-         * Returns list of garbage.
-         * @return List with thread garbage.
-         */
-        public List<Object> getList(){
-            return garbage;
-        }
-
-        @Override
-        public void run() {
-            System.out.println("Start the thread " + threadId);
-            while (TestStressIHOPMultiThread.this.isRunning()) {
-                allocate(amountOfGarbage);
-                free();
-            }
-        }
-
-        private void silentJoin() {
-            System.out.println("Join the thread " + threadId);
-            try {
-                join();
-            } catch (InterruptedException ie) {
-                throw new RuntimeException(ie);
-            }
-        }
-
-        /**
-         * Allocates thread local garbage
-         */
-        private void allocate(long amount) {
-            long allocated = 0;
-            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
-                garbage.add(new byte[CHUNK_SIZE]);
-                allocated += CHUNK_SIZE;
-            }
-        }
-
-        /**
-         * Frees thread local garbage
-         */
-        private void free() {
-            garbage.clear();
-        }
-    }
-}
--- a/test/stress/gc/TestStressRSetCoarsening.java	Thu Apr 14 19:55:39 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,335 +0,0 @@
-/*
- * Copyright (c) 2016, 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.
- */
-
-import java.util.concurrent.TimeoutException;
-import sun.hotspot.WhiteBox;
-
-/*
- * @test TestStressRSetCoarsening.java
- * @key stress
- * @bug 8146984 8147087
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @requires os.maxMemory > 3G
- *
- * @summary Stress G1 Remembered Set by creating a lot of cross region links
- * @modules java.base/jdk.internal.misc
- * @library /testlibrary /test/lib
- * @build sun.hotspot.WhiteBox
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  1  0 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx500m -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  1 10 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx500m -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 42 10 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  2 0 300
- * @run main/othervm/timeout=1800
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 500 0  1800
- * @run main/othervm/timeout=1800
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
- *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
- *     -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 10  10 1800
- */
-
-/**
- * What the test does.
- * Preparation stage:
- *   Fill out ~90% of the heap with objects, each object is an object array.
- *   If we want to allocate K objects per region, we calculate N to meet:
- *      sizeOf(Object[N]) ~= regionSize / K
- * Stress stage:
- *   No more allocation, so no more GC.
- *   We will perform a number of  iterations. On each iteration i,
- *   for each pair of regions Rx and Ry we will set c[i] references
- *   from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
- *   concurrent mark cycle will be initiated (to recalculate remembered sets).
- *   As the result RSet will be growing up and down, up and down many times.
- *
- * The test expects: no crash and no timeouts.
- *
- * Test Parameters:
- *   args[0] - number of objects per Heap Region (1 - means humongous)
- *   args[1] - number of regions to refresh to provoke GC at the end of cycle.
- *             (0 - means no GC, i.e. no reading from RSet)
- *   args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
- */
-public class TestStressRSetCoarsening {
-
-    public static void main(String... args) throws InterruptedException {
-        if (args.length != 3) {
-            throw new IllegalArgumentException("Wrong number of arguments " + args.length);
-        }
-        int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
-        int regsToRefresh = Integer.parseInt(args[1]);  // 0 means no regions to refresh at the end of cycle
-        int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
-        new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
-    }
-
-    private static final long KB = 1024;
-    private static final long MB = 1024 * KB;
-
-    private static final WhiteBox WB = WhiteBox.getWhiteBox();
-
-    public final Object[][] storage;
-
-    /**
-     * Number of objects per region. This is a test parameter.
-     */
-    public final int K;
-
-    /**
-     * Length of object array: sizeOf(Object[N]) ~= regionSize / K
-     * N will be calculated as function of K.
-     */
-    public final int N;
-
-    /**
-     * How many regions involved into testing.
-     * Will be calculated as heapFractionToAllocate * freeRegionCount.
-     */
-    public final int regionCount;
-
-    /**
-     * How much heap to use.
-     */
-    public final float heapFractionToAllocate = 0.9f;
-
-    /**
-     * How many regions to be refreshed at the end of cycle.
-     * This is a test parameter.
-     */
-    public final int regsToRefresh;
-
-    /**
-     * Initial time.
-     */
-    public final long start;
-
-    /**
-     * Time when the test should stop working.
-     */
-    public final long finishAt;
-
-    /**
-     * Does pre-calculation and allocate necessary objects.
-     *
-     * @param objPerRegions how many objects per G1 heap region
-     */
-    TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
-        this.K = objPerRegions;
-        this.regsToRefresh = regsToRefresh;
-        this.start = System.currentTimeMillis();
-        this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
-
-        long regionSize = WB.g1RegionSize();
-
-        // How many free regions
-        Runtime rt = Runtime.getRuntime();
-        long used = rt.totalMemory() - rt.freeMemory();
-        long totalFree = rt.maxMemory() - used;
-        regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
-        long toAllocate = regionCount * regionSize;
-        System.out.println("%% Test parameters");
-        System.out.println("%%   Objects per region              : " + K);
-        System.out.println("%%   Heap fraction to allocate       : " + (int) (heapFractionToAllocate * 100) + "%");
-        System.out.println("%%   Regions to refresh to provoke GC: " + regsToRefresh);
-
-        System.out.println("%% Memory");
-        System.out.println("%%   used          :        " + used / MB + "M");
-        System.out.println("%%   available     :        " + totalFree / MB + "M");
-        System.out.println("%%   to allocate   :        " + toAllocate / MB + "M");
-        System.out.println("%%     (in regs)   :        " + regionCount);
-        System.out.println("%%   G1 Region Size:        " + regionSize / MB + "M");
-
-        int refSize = WB.getHeapOopSize();
-
-        // Calculate N:    K*sizeOf(Object[N]) ~= regionSize
-        //                 sizeOf(Object[N]) ~=  (N+4)*refSize
-        // ==>
-        //                 N = regionSize / K / refSize - 4;
-        N = (int) ((regionSize / K) / refSize) - 5;
-
-        /*
-         *   --------------
-         *   region0   storage[0]        = new Object[N]
-         *             ...
-         *             storage[K-1]      = new Object[N]
-         *   ---------------
-         *   region1   storage[K]        = new Object[N]
-         *             ...
-         *             storage[2*K - 1]  = new Object[N]
-         *   --------------
-         *   ...
-         *   --------------
-         *   regionX   storage[X*K]         = new Object[N]
-         *             ...
-         *             storage[(X+1)*K -1]  = new Object[N]
-         *    where X = HeapFraction * TotalRegions
-         *   -------------
-         */
-        System.out.println("%% Objects");
-        System.out.println("%%   N (array length)      : " + N);
-        System.out.println("%%   K (objects in regions): " + K);
-        System.out.println("%%   Reference size        : " + refSize);
-        System.out.println("%%   Approximate obj size  : " + (N + 2) * refSize / KB + "K)");
-
-        storage = new Object[regionCount * K][];
-        for (int i = 0; i < storage.length; i++) {
-            storage[i] = new Object[N];
-        }
-    }
-
-    public void go() throws InterruptedException {
-        // threshold for sparce -> fine
-        final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
-
-        // threshold for fine -> coarse
-        final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
-
-        // regToRegRefCounts - array of reference counts from region to region
-        // at the the end of iteration.
-        // The number of test iterations is array length - 1.
-        // If c[i] > c[i-1] then during the iteration i more references will
-        // be created.
-        // If c[i] < c[i-1] then some referenes will be cleaned.
-        int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
-            COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
-
-        // For progress tracking
-        int[] progress = new int[regToRegRefCounts.length];
-        progress[0] = 0;
-        for (int i = 1; i < regToRegRefCounts.length; i++) {
-            progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
-        }
-        try {
-            for (int i = 1; i < regToRegRefCounts.length; i++) {
-                int pre = regToRegRefCounts[i - 1];
-                int cur = regToRegRefCounts[i];
-                float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
-
-                System.out.println("%% step " + i
-                        + " out of " + (regToRegRefCounts.length - 1)
-                        + " (~" + (int) (100 * prog) + "% done)");
-                System.out.println("%%      " + pre + "  --> " + cur);
-                for (int to = 0; to < regionCount; to++) {
-                    // Select a celebrity object that we will install references to.
-                    // The celebrity will be referred from all other regions.
-                    // If the number of references after should be less than they
-                    // were before, select NULL.
-                    Object celebrity = cur > pre ? storage[to * K] : null;
-                    for (int from = 0; from < regionCount; from++) {
-                        if (to == from) {
-                            continue; // no need to refer to itself
-                        }
-
-                        int step = cur > pre ? +1 : -1;
-                        for (int rn = pre; rn != cur; rn += step) {
-                            storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
-                            if (System.currentTimeMillis() > finishAt) {
-                                throw new TimeoutException();
-                            }
-                        }
-                    }
-                }
-                if (pre > cur) {
-                    // Number of references went down.
-                    // Need to provoke recalculation of RSet.
-                    WB.g1StartConcMarkCycle();
-                    while (WB.g1InConcurrentMark()) {
-                        Thread.sleep(1);
-                    }
-                }
-
-                // To force the use of rememebered set entries we need to provoke a GC.
-                // To induce some fragmentation, and some mixed GCs, we need
-                // to make a few objects unreachable.
-                for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
-                    int to = toClean % regionCount;
-                    // Need to remove all references from all regions to the region 'to'
-                    for (int from = 0; from < regionCount; from++) {
-                        if (to == from) {
-                            continue; // no need to refer to itself
-                        }
-                        for (int rn = 0; rn <= cur; rn++) {
-                            storage[getY(to, from, rn)][getX(to, from, rn)] = null;
-                        }
-                    }
-                    // 'Refresh' storage elements for the region 'to'
-                    // After that loop all 'old' objects in the region 'to'
-                    // should become unreachable.
-                    for (int k = 0; k < K; k++) {
-                        storage[(to * K + k) % storage.length] = new Object[N];
-                    }
-                }
-            }
-        } catch (TimeoutException e) {
-            System.out.println("%% TIMEOUT!!!");
-        }
-        long now = System.currentTimeMillis();
-        System.out.println("%% Summary");
-        System.out.println("%%   Time spent          : " + ((now - start) / 1000) + " seconds");
-        System.out.println("%%   Free memory left    : " + Runtime.getRuntime().freeMemory() / KB + "K");
-        System.out.println("%% Test passed");
-    }
-
-    /**
-     * Returns X index in the Storage of the reference #rn from the region
-     * 'from' to the region 'to'.
-     *
-     * @param to region # to refer to
-     * @param from region # to refer from
-     * @param rn number of reference
-     *
-     * @return X index in the range: [0 ... N-1]
-     */
-    private int getX(int to, int from, int rn) {
-        return (rn * regionCount + to) % N;
-    }
-
-    /**
-     * Returns Y index in the Storage of the reference #rn from the region
-     * 'from' to the region 'to'.
-     *
-     * @param to region # to refer to
-     * @param from region # to refer from
-     * @param rn number of reference
-     *
-     * @return Y index in the range: [0 ... K*regionCount -1]
-     */
-    private int getY(int to, int from, int rn) {
-        return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
-    }
-}
-