# HG changeset patch
# User zgu
# Date 1582650095 18000
#      Tue Feb 25 12:01:35 2020 -0500
# Node ID df62c177841eeb85dcb91ec744487fe90cdfd7be
# Parent  ce1281b3e5aa0e7c2bedc5a62d44a2450c649606
[backport] 8239926: Shenandoah: Shenandoah needs to mark nmethod's metadata
Reviewed-by: rkennke, shade

diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
@@ -215,14 +215,15 @@
   }
 };
 
-class ShenandoahSATBThreadsClosure : public ThreadClosure {
+class ShenandoahSATBAndRemarkCodeRootsThreadsClosure : public ThreadClosure {
 private:
   ShenandoahSATBBufferClosure* _satb_cl;
+  MarkingCodeBlobClosure*              _code_cl;
   int _thread_parity;
 
 public:
-  ShenandoahSATBThreadsClosure(ShenandoahSATBBufferClosure* satb_cl) :
-    _satb_cl(satb_cl),
+  ShenandoahSATBAndRemarkCodeRootsThreadsClosure(ShenandoahSATBBufferClosure* satb_cl, MarkingCodeBlobClosure* code_cl) :
+    _satb_cl(satb_cl), _code_cl(code_cl),
     _thread_parity(SharedHeap::heap()->strong_roots_parity()) {}
 
   void do_thread(Thread* thread) {
@@ -230,6 +231,15 @@
       if (thread->claim_oops_do(true, _thread_parity)) {
         JavaThread* jt = (JavaThread*)thread;
         jt->satb_mark_queue().apply_closure_and_empty(_satb_cl);
+        if (_code_cl != NULL) {
+          // In theory it should not be neccessary to explicitly walk the nmethods to find roots for concurrent marking
+          // however the liveness of oops reachable from nmethods have very complex lifecycles:
+          // * Alive if on the stack of an executing method
+          // * Weakly reachable otherwise
+          // Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be
+          // live by the SATB invariant but other oops recorded in nmethods may behave differently.
+          jt->nmethods_do(_code_cl);
+        }
       }
     } else if (thread->is_VM_thread()) {
       if (thread->claim_oops_do(true, _thread_parity)) {
@@ -253,6 +263,14 @@
   void work(uint worker_id) {
     ShenandoahHeap* heap = ShenandoahHeap::heap();
 
+    ReferenceProcessor* rp;
+    if (heap->process_references()) {
+      rp = heap->ref_processor();
+      shenandoah_assert_rp_isalive_installed();
+    } else {
+      rp = NULL;
+    }
+
     // First drain remaining SATB buffers.
     // Notice that this is not strictly necessary for mark-compact. But since
     // it requires a StrongRootsScope around the task, we need to claim the
@@ -267,16 +285,22 @@
       ShenandoahSATBBufferClosure cl(q, dq);
       SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
       while (satb_mq_set.apply_closure_to_completed_buffer(&cl));
-      ShenandoahSATBThreadsClosure tc(&cl);
-      Threads::threads_do(&tc);
-    }
-
-    ReferenceProcessor* rp;
-    if (heap->process_references()) {
-      rp = heap->ref_processor();
-      shenandoah_assert_rp_isalive_installed();
-    } else {
-      rp = NULL;
+      if (heap->unload_classes()) {
+        if (heap->has_forwarded_objects()) {
+          ShenandoahMarkResolveRefsClosure resolve_mark_cl(q, rp);
+          MarkingCodeBlobClosure blobsCl(&resolve_mark_cl, !CodeBlobToOopClosure::FixRelocations);
+          ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, &blobsCl);
+          Threads::threads_do(&tc);
+        } else {
+          ShenandoahMarkRefsClosure mark_cl(q, rp);
+          MarkingCodeBlobClosure blobsCl(&mark_cl, !CodeBlobToOopClosure::FixRelocations);
+          ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, &blobsCl);
+          Threads::threads_do(&tc);
+        }
+      } else {
+        ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, NULL);
+        Threads::threads_do(&tc);
+      }
     }
 
     if (heap->is_degenerated_gc_in_progress()) {
# HG changeset patch
# User roland
# Date 1585042297 -3600
#      Tue Mar 24 10:31:37 2020 +0100
# Node ID c30b6a2e27c434134a1c2821ee7896aacc5fcc89
# Parent  df62c177841eeb85dcb91ec744487fe90cdfd7be
[backport] 8241675: Shenandoah: assert(n->outcnt() > 0) at shenandoahSupport.cpp:2858 with java/util/Collections/FindSubList.java
Reviewed-by: rkennke

diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
@@ -2306,41 +2306,6 @@
               bool create_phi = true;
               if (_phase->is_dominator(new_ctrl, u)) {
                 create_phi = false;
-              } else if (!_phase->C->has_irreducible_loop()) {
-                IdealLoopTree* loop = _phase->get_loop(ctrl);
-                bool do_check = true;
-                IdealLoopTree* l = loop;
-                create_phi = false;
-                while (l != _phase->ltree_root()) {
-                  Node* head = l->_head;
-                  if (head->in(0) == NULL) {
-                    head = _phase->get_ctrl(head);
-                  }
-                  if (_phase->is_dominator(head, u) && _phase->is_dominator(_phase->idom(u), head)) {
-                    create_phi = true;
-                    do_check = false;
-                    break;
-                  }
-                  l = l->_parent;
-                }
-
-                if (do_check) {
-                  assert(!create_phi, "");
-                  IdealLoopTree* u_loop = _phase->get_loop(u);
-                  if (u_loop != _phase->ltree_root() && u_loop->is_member(loop)) {
-                    Node* c = ctrl;
-                    while (!_phase->is_dominator(c, u_loop->tail())) {
-                      c = _phase->idom(c);
-                    }
-                    if (!_phase->is_dominator(c, u)) {
-                      do_check = false;
-                    }
-                  }
-                }
-
-                if (do_check && _phase->is_dominator(_phase->idom(u), new_ctrl)) {
-                  create_phi = true;
-                }
               }
               if (create_phi) {
                 Node* phi = new (_phase->C) PhiNode(u, Type::MEMORY, _phase->C->get_adr_type(_alias));
# HG changeset patch
# User rkennke
# Date 1585309656 -3600
#      Fri Mar 27 12:47:36 2020 +0100
# Node ID f33666b9f05e3adddb0779412bb4fcf41fc6c571
# Parent  c30b6a2e27c434134a1c2821ee7896aacc5fcc89
[backport] 8241700: Shenandoah: Fold ShenandoahKeepAliveBarrier flag into ShenandoahSATBBarrier
Reviewed-by: shade

diff --git a/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
--- a/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
+++ b/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
@@ -1944,7 +1944,7 @@
     __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value));
     __ verify_oop(r0);
 #if INCLUDE_ALL_GCS
-    if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+    if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
       __ g1_write_barrier_pre(noreg /* obj */,
                               r0 /* pre_val */,
                               rthread /* thread */,
diff --git a/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
--- a/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
+++ b/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
@@ -693,7 +693,7 @@
   const int referent_offset = java_lang_ref_Reference::referent_offset;
   guarantee(referent_offset > 0, "referent offset not initialized");
 
-  if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+  if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
     Label slow_path;
     const Register local_0 = c_rarg0;
     // Check if local 0 != NULL
@@ -1187,7 +1187,7 @@
     // Resolve jweak.
     __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value));
 #if INCLUDE_ALL_GCS
-    if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+    if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
       __ enter();                   // Barrier may call runtime.
       __ g1_write_barrier_pre(noreg /* obj */,
                               r0 /* pre_val */,
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
@@ -863,7 +863,7 @@
 
     // Generate the G1 pre-barrier code to log the value of
     // the referent field in an SATB buffer.
-    if (!UseShenandoahGC || ShenandoahKeepAliveBarrier) {
+    if (!UseShenandoahGC || ShenandoahSATBBarrier) {
     __ get_thread(rcx);
     __ g1_write_barrier_pre(noreg /* obj */,
                             rax /* pre_val */,
diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
@@ -815,7 +815,7 @@
 
     // Generate the G1 pre-barrier code to log the value of
     // the referent field in an SATB buffer.
-    if (!UseShenandoahGC || ShenandoahKeepAliveBarrier) {
+    if (!UseShenandoahGC || ShenandoahSATBBarrier) {
       if (UseShenandoahGC) __ push_IU_state();
     __ g1_write_barrier_pre(noreg /* obj */,
                             rax /* pre_val */,
diff --git a/src/share/vm/classfile/symbolTable.cpp b/src/share/vm/classfile/symbolTable.cpp
--- a/src/share/vm/classfile/symbolTable.cpp
+++ b/src/share/vm/classfile/symbolTable.cpp
@@ -721,7 +721,7 @@
   // considered dead. The SATB part of G1 needs to get notified about this
   // potential resurrection, otherwise the marking might not find the object.
 #if INCLUDE_ALL_GCS
-  if ((UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) && string != NULL) {
+  if ((UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) && string != NULL) {
     G1SATBCardTableModRefBS::enqueue(string);
   }
 #endif
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
@@ -45,7 +45,6 @@
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
@@ -44,7 +44,6 @@
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
@@ -37,7 +37,6 @@
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
@@ -217,12 +217,6 @@
   }
 }
 
-void ShenandoahBarrierSet::keep_alive_barrier(oop obj) {
-  if (ShenandoahKeepAliveBarrier && _heap->is_concurrent_mark_in_progress()) {
-    enqueue(obj);
-  }
-}
-
 void ShenandoahBarrierSet::enqueue(oop obj) {
   assert(JavaThread::satb_mark_queue_set().shared_satb_queue()->is_active(), "only get here when SATB active");
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
@@ -111,7 +111,6 @@
   static inline oop resolve_forwarded(oop p);
 
   void storeval_barrier(oop obj);
-  void keep_alive_barrier(oop obj);
 
   oop load_reference_barrier(oop obj);
   oop load_reference_barrier_mutator(oop obj);
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
@@ -35,7 +35,6 @@
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahKeepAliveBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.cpp
@@ -42,7 +42,6 @@
   // Disable known barriers by default.
   SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahLoadRefBarrier);
   SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahSATBBarrier);
-  SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahKeepAliveBarrier);
   SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCASBarrier);
   SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier);
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
@@ -316,9 +316,6 @@
   diagnostic(bool, ShenandoahSATBBarrier, true,                             \
           "Turn on/off SATB barriers in Shenandoah")                        \
                                                                             \
-  diagnostic(bool, ShenandoahKeepAliveBarrier, true,                        \
-          "Turn on/off keep alive barriers in Shenandoah")                  \
-                                                                            \
   diagnostic(bool, ShenandoahStoreValEnqueueBarrier, false,                 \
           "Turn on/off enqueuing of oops for storeval barriers")            \
                                                                             \
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -2630,7 +2630,7 @@
   // If G1 is enabled and we are accessing the value of the referent
   // field in a reference object then we need to register a non-null
   // referent with the SATB barrier.
-  if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+  if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
     bool needs_barrier = false;
 
     if (ret != NULL &&
diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
--- a/src/share/vm/prims/jvm.cpp
+++ b/src/share/vm/prims/jvm.cpp
@@ -589,7 +589,7 @@
   // If G1 is enabled then we need to register a non-null referent
   // with the SATB barrier.
 #if INCLUDE_ALL_GCS
-  if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+  if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
     oop referent = java_lang_ref_Reference::referent(clone);
     if (referent != NULL) {
       G1SATBCardTableModRefBS::enqueue(referent);
diff --git a/src/share/vm/prims/jvmtiGetLoadedClasses.cpp b/src/share/vm/prims/jvmtiGetLoadedClasses.cpp
--- a/src/share/vm/prims/jvmtiGetLoadedClasses.cpp
+++ b/src/share/vm/prims/jvmtiGetLoadedClasses.cpp
@@ -46,7 +46,7 @@
   // to get notified about this potential resurrection, otherwise the marking
   // might not find the object.
 #if INCLUDE_ALL_GCS
-  if ((o != NULL) && (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier))) {
+  if ((o != NULL) && (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier))) {
     G1SATBCardTableModRefBS::enqueue(o);
   }
 #endif
diff --git a/src/share/vm/prims/jvmtiTagMap.cpp b/src/share/vm/prims/jvmtiTagMap.cpp
--- a/src/share/vm/prims/jvmtiTagMap.cpp
+++ b/src/share/vm/prims/jvmtiTagMap.cpp
@@ -1521,7 +1521,7 @@
         oop o = entry->object();
         assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
 #if INCLUDE_ALL_GCS
-        if (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) {
+        if (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) {
           // The reference in this tag map could be the only (implicitly weak)
           // reference to that object. If we hand it out, we need to keep it live wrt
           // SATB marking similar to other j.l.ref.Reference referents.
diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
--- a/src/share/vm/prims/unsafe.cpp
+++ b/src/share/vm/prims/unsafe.cpp
@@ -218,7 +218,7 @@
 
 static void ensure_satb_referent_alive(oop o, jlong offset, oop v) {
 #if INCLUDE_ALL_GCS
-  if ((UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier)) && v != NULL && is_java_lang_ref_Reference_access(o, offset)) {
+  if ((UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier)) && v != NULL && is_java_lang_ref_Reference_access(o, offset)) {
     G1SATBCardTableModRefBS::enqueue(v);
   }
 #endif
diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp
--- a/src/share/vm/runtime/arguments.cpp
+++ b/src/share/vm/runtime/arguments.cpp
@@ -1733,7 +1733,6 @@
 
   FLAG_SET_DEFAULT(ShenandoahSATBBarrier,            false);
   FLAG_SET_DEFAULT(ShenandoahLoadRefBarrier,         false);
-  FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier,       false);
   FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, false);
   FLAG_SET_DEFAULT(ShenandoahCASBarrier,             false);
   FLAG_SET_DEFAULT(ShenandoahCloneBarrier,           false);
@@ -1846,7 +1845,6 @@
   if (ShenandoahVerifyOptoBarriers &&
           (!FLAG_IS_DEFAULT(ShenandoahSATBBarrier)    ||
            !FLAG_IS_DEFAULT(ShenandoahLoadRefBarrier) ||
-           !FLAG_IS_DEFAULT(ShenandoahKeepAliveBarrier)       ||
            !FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier) ||
            !FLAG_IS_DEFAULT(ShenandoahCASBarrier)     ||
            !FLAG_IS_DEFAULT(ShenandoahCloneBarrier)
diff --git a/src/share/vm/runtime/jniHandles.cpp b/src/share/vm/runtime/jniHandles.cpp
--- a/src/share/vm/runtime/jniHandles.cpp
+++ b/src/share/vm/runtime/jniHandles.cpp
@@ -116,7 +116,7 @@
   oop result = jweak_ref(handle);
   result = guard_value<external_guard>(result);
 #if INCLUDE_ALL_GCS
-  if (result != NULL && (UseG1GC || (UseShenandoahGC && ShenandoahKeepAliveBarrier))) {
+  if (result != NULL && (UseG1GC || (UseShenandoahGC && ShenandoahSATBBarrier))) {
     G1SATBCardTableModRefBS::enqueue(result);
   }
 #endif // INCLUDE_ALL_GCS
diff --git a/test/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
--- a/test/gc/shenandoah/options/TestWrongBarrierDisable.java
+++ b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
@@ -40,7 +40,6 @@
                 "ShenandoahCASBarrier",
                 "ShenandoahCloneBarrier",
                 "ShenandoahSATBBarrier",
-                "ShenandoahKeepAliveBarrier",
         };
 
         shouldFailAll("-XX:ShenandoahGCHeuristics=adaptive",   concurrent);
# HG changeset patch
# User rkennke
# Date 1586173527 -7200
#      Mon Apr 06 13:45:27 2020 +0200
# Node ID fcf19e0cd2c176e1f2f95e4a880cebfa0650e954
# Parent  f33666b9f05e3adddb0779412bb4fcf41fc6c571
[backport] 8242130: Shenandoah: Simplify arraycopy-barrier dispatching
Reviewed-by: shade

diff --git a/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp b/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
+++ b/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
@@ -49,7 +49,7 @@
     // Avoid calling runtime if count == 0
     __ cbz(count, done);
 
-    // Is marking active?
+    // Is GC active?
     Address gc_state(rthread, in_bytes(JavaThread::gc_state_offset()));
     __ ldrb(rscratch1, gc_state);
     if (dest_uninitialized) {
@@ -62,17 +62,9 @@
 
     __ push_call_clobbered_registers();
     if (UseCompressedOops) {
-      if (dest_uninitialized) {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry), src, dst, count);
-      } else {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), src, dst, count);
-      }
+        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);
     } else {
-      if (dest_uninitialized) {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry), src, dst, count);
-      } else {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), src, dst, count);
-      }
+        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);
     }
     __ pop_call_clobbered_registers();
     __ bind(done);
diff --git a/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp b/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
--- a/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
+++ b/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
@@ -67,7 +67,7 @@
     __ testptr(count, count);
     __ jcc(Assembler::zero, done);
 
-    // Avoid runtime call when not marking.
+    // Avoid runtime call when not active.
     Address gc_state(thread, in_bytes(JavaThread::gc_state_offset()));
     int flags = ShenandoahHeap::HAS_FORWARDED;
     if (!dest_uninitialized) {
@@ -77,6 +77,7 @@
     __ jcc(Assembler::zero, done);
 
     __ pusha();                      // push registers
+
 #ifdef _LP64
     assert(src == rdi, "expected");
     assert(dst == rsi, "expected");
@@ -84,20 +85,15 @@
     // register into right place.
     // assert(count == rdx, "expected");
     if (UseCompressedOops) {
-      if (dest_uninitialized) {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry), src, dst, count);
-      } else {
-        __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry), src, dst, count);
-      }
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry),
+                        src, dst, count);
     } else
 #endif
-      {
-        if (dest_uninitialized) {
-          __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry), src, dst, count);
-        } else {
-          __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_pre_oop_entry), src, dst, count);
-        }
-      }
+    {
+      __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry),
+                      src, dst, count);
+    }
+
     __ popa();
     __ bind(done);
     NOT_LP64(__ pop(thread);)
diff --git a/src/share/vm/c1/c1_Runtime1.cpp b/src/share/vm/c1/c1_Runtime1.cpp
--- a/src/share/vm/c1/c1_Runtime1.cpp
+++ b/src/share/vm/c1/c1_Runtime1.cpp
@@ -1313,7 +1313,7 @@
 
 #if INCLUDE_ALL_GCS
   if (UseShenandoahGC) {
-    ShenandoahBarrierSet::barrier_set()->arraycopy_pre(src_addr, dst_addr, length);
+    ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src_addr, dst_addr, length);
   }
 #endif
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
@@ -39,7 +39,7 @@
   ShenandoahBarrierSetC1* const _bsc1;
   ShenandoahBarrierSetC2* const _bsc2;
 
-  inline bool skip_bulk_update(HeapWord* dst);
+  inline bool need_bulk_update(HeapWord* dst);
 public:
   ShenandoahBarrierSet(ShenandoahHeap* heap);
 
@@ -85,13 +85,8 @@
 
   void write_ref_array_work(MemRegion mr) {}
 
-  template <class T> void
-  write_ref_array_pre_work(T* src, T* dst, size_t count, bool dest_uninitialized);
-
-  inline void arraycopy_pre(oop* src, oop* dst, size_t count);
-  inline void arraycopy_pre(narrowOop* src, narrowOop* dst, size_t count);
-  inline void arraycopy_update(oop* src, size_t count);
-  inline void arraycopy_update(narrowOop* src, size_t count);
+  template <class T>
+  inline void arraycopy_barrier(T* src, T* dst, size_t count);
   inline void clone_barrier(oop src);
   void clone_barrier_runtime(oop src);
 
@@ -122,11 +117,14 @@
 
 private:
   template <class T>
-  inline void arraycopy_pre_work(T* src, T* dst, size_t count);
+  inline void arraycopy_marking(T* ary, size_t count);
+  template <class T>
+  inline void arraycopy_evacuation(T* src, size_t count);
+  template <class T>
+  inline void arraycopy_update(T* src, size_t count);
+
   template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
   inline void arraycopy_work(T* src, size_t count);
-  template <class T>
-  inline void arraycopy_update_impl(T* src, size_t count);
 
   oop load_reference_barrier_impl(oop obj);
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
@@ -74,46 +74,47 @@
 }
 
 template <class T>
-void ShenandoahBarrierSet::arraycopy_pre_work(T* src, T* dst, size_t count) {
-  if (_heap->is_concurrent_mark_in_progress() &&
-      !_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(dst))) {
-    arraycopy_work<T, false, false, true>(dst, count);
+void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) {
+  if (count == 0) {
+    return;
   }
-
-  if (_heap->has_forwarded_objects()) {
-    arraycopy_update_impl(src, count);
+  int gc_state = _heap->gc_state();
+  if ((gc_state & ShenandoahHeap::MARKING) != 0) {
+    arraycopy_marking(dst, count);
+  } else if ((gc_state & ShenandoahHeap::EVACUATION) != 0) {
+    arraycopy_evacuation(src, count);
+  } else if ((gc_state & ShenandoahHeap::UPDATEREFS) != 0) {
+    arraycopy_update(src, count);
   }
 }
 
-void ShenandoahBarrierSet::arraycopy_pre(oop* src, oop* dst, size_t count) {
-  arraycopy_pre_work(src, dst, count);
+template <class T>
+void ShenandoahBarrierSet::arraycopy_marking(T* array, size_t count) {
+  assert(_heap->is_concurrent_mark_in_progress(), "only during marking");
+  if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(array))) {
+    arraycopy_work<T, false, false, true>(array, count);
+  }
 }
 
-void ShenandoahBarrierSet::arraycopy_pre(narrowOop* src, narrowOop* dst, size_t count) {
-  arraycopy_pre_work(src, dst, count);
-}
-
-inline bool ShenandoahBarrierSet::skip_bulk_update(HeapWord* dst) {
-  return dst >= _heap->heap_region_containing(dst)->get_update_watermark();
+inline bool ShenandoahBarrierSet::need_bulk_update(HeapWord* ary) {
+  return ary < _heap->heap_region_containing(ary)->get_update_watermark();
 }
 
 template <class T>
-void ShenandoahBarrierSet::arraycopy_update_impl(T* src, size_t count) {
-  if (skip_bulk_update(reinterpret_cast<HeapWord*>(src))) return;
-  if (_heap->is_evacuation_in_progress()) {
+void ShenandoahBarrierSet::arraycopy_evacuation(T* src, size_t count) {
+  assert(_heap->is_evacuation_in_progress(), "only during evacuation");
+  if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
     ShenandoahEvacOOMScope oom_evac;
     arraycopy_work<T, true, true, false>(src, count);
-  } else if (_heap->has_forwarded_objects()) {
+  }
+}
+
+template <class T>
+void ShenandoahBarrierSet::arraycopy_update(T* src, size_t count) {
+  assert(_heap->is_update_refs_in_progress(), "only during update-refs");
+  if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
     arraycopy_work<T, true, false, false>(src, count);
   }
 }
 
-void ShenandoahBarrierSet::arraycopy_update(oop* src, size_t count) {
-  arraycopy_update_impl(src, count);
-}
-
-void ShenandoahBarrierSet::arraycopy_update(narrowOop* src, size_t count) {
-  arraycopy_update_impl(src, count);
-}
-
 #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
@@ -80,7 +80,7 @@
   // that potentially need to be updated.
  
   shenandoah_assert_correct(NULL, obj);
-  if (skip_bulk_update(cast_from_oop<HeapWord*>(obj))) return;
+  if (!need_bulk_update(cast_from_oop<HeapWord*>(obj))) return;
   if (_heap->is_evacuation_in_progress()) {
     ShenandoahEvacOOMScope evac_scope;
     ShenandoahUpdateRefsForOopClosure</* evac = */ true, /* enqueue */ false> cl;
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
@@ -28,24 +28,14 @@
 #include "runtime/interfaceSupport.hpp"
 #include "oops/oop.inline.hpp"
 
-void ShenandoahRuntime::write_ref_array_pre_oop_entry(oop* src, oop* dst, size_t length) {
+void ShenandoahRuntime::arraycopy_barrier_oop_entry(oop* src, oop* dst, size_t length) {
   ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
-  bs->arraycopy_pre(src, dst, length);
+  bs->arraycopy_barrier(src, dst, length);
 }
 
-void ShenandoahRuntime::write_ref_array_pre_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) {
-  ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
-  bs->arraycopy_pre(src, dst, length);
-}
-
-void ShenandoahRuntime::write_ref_array_pre_duinit_oop_entry(oop* src, oop* dst, size_t length) {
+void ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) {
   ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
-  bs->arraycopy_update(src, length);
-}
-
-void ShenandoahRuntime::write_ref_array_pre_duinit_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) {
-  ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set();
-  bs->arraycopy_update(src, length);
+  bs->arraycopy_barrier(src, dst, length);
 }
 
 // Shenandoah pre write barrier slowpath
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.hpp
@@ -33,10 +33,9 @@
 
 class ShenandoahRuntime : public AllStatic {
 public:
-  static void write_ref_array_pre_oop_entry(oop* src, oop* dst, size_t length);
-  static void write_ref_array_pre_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length);
-  static void write_ref_array_pre_duinit_oop_entry(oop* src, oop* dst, size_t length);
-  static void write_ref_array_pre_duinit_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length);
+  static void arraycopy_barrier_oop_entry(oop* src, oop* dst, size_t length);
+  static void arraycopy_barrier_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length);
+
   static void write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread);
 
   static oopDesc* load_reference_barrier(oopDesc* src);
diff --git a/src/share/vm/oops/objArrayKlass.cpp b/src/share/vm/oops/objArrayKlass.cpp
--- a/src/share/vm/oops/objArrayKlass.cpp
+++ b/src/share/vm/oops/objArrayKlass.cpp
@@ -247,7 +247,7 @@
 
 #if INCLUDE_ALL_GCS
   if (UseShenandoahGC) {
-    ShenandoahBarrierSet::barrier_set()->arraycopy_pre(src, dst, length);
+    ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length);
   }
 #endif
 
# HG changeset patch
# User rkennke
# Date 1586183344 -7200
#      Mon Apr 06 16:29:04 2020 +0200
# Node ID fb9ff8b01d3ac331309e9cee05e02e0f75284366
# Parent  fcf19e0cd2c176e1f2f95e4a880cebfa0650e954
[backport] 8242217: Shenandoah: Enable GC mode to be diagnostic/experimental and have a name
Reviewed-by: shade

diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
@@ -397,6 +397,19 @@
     ShouldNotReachHere();
   }
   _gc_mode->initialize_flags();
+  if (_gc_mode->is_diagnostic() && !UnlockDiagnosticVMOptions) {
+    vm_exit_during_initialization(
+            err_msg("GC mode \"%s\" is diagnostic, and must be enabled via -XX:+UnlockDiagnosticVMOptions.",
+                    _gc_mode->name()));
+  }
+  if (_gc_mode->is_experimental() && !UnlockExperimentalVMOptions) {
+    vm_exit_during_initialization(
+            err_msg("GC mode \"%s\" is experimental, and must be enabled via -XX:+UnlockExperimentalVMOptions.",
+                    _gc_mode->name()));
+  }
+  log_info(gc, init)("Shenandoah GC mode: %s",
+                     _gc_mode->name());
+
   _heuristics = _gc_mode->initialize_heuristics();
 
   if (_heuristics->is_diagnostic() && !UnlockDiagnosticVMOptions) {
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
@@ -32,6 +32,9 @@
 public:
   virtual void initialize_flags() const = 0;
   virtual ShenandoahHeuristics* initialize_heuristics() const = 0;
+  virtual const char* name() = 0;
+  virtual bool is_diagnostic() = 0;
+  virtual bool is_experimental() = 0;
 };
 
 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMODE_HPP
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.hpp
@@ -32,6 +32,9 @@
 public:
   virtual void initialize_flags() const;
   virtual ShenandoahHeuristics* initialize_heuristics() const;
+  virtual const char* name()     { return "Normal"; }
+  virtual bool is_diagnostic()   { return false; }
+  virtual bool is_experimental() { return false; }
 };
 
 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHNORMALMODE_HPP
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahPassiveMode.hpp
@@ -30,6 +30,10 @@
 public:
   virtual void initialize_flags() const;
   virtual ShenandoahHeuristics* initialize_heuristics() const;
+
+  virtual const char* name()     { return "Passive"; }
+  virtual bool is_diagnostic()   { return true; }
+  virtual bool is_experimental() { return false; }
 };
 
 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHNORMALMODE_HPP
# HG changeset patch
# User rkennke
# Date 1586185726 -7200
#      Mon Apr 06 17:08:46 2020 +0200
# Node ID a222813e5654b4a6809ad0233238300f862565c2
# Parent  fb9ff8b01d3ac331309e9cee05e02e0f75284366
[backport] 8242054: Shenandoah: New incremental-update mode
Reviewed-by: shade

diff --git a/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp b/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
+++ b/src/cpu/aarch64/vm/shenandoahBarrierSetAssembler_aarch64.cpp
@@ -42,7 +42,7 @@
 
 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, bool dest_uninitialized,
                                                        Register src, Register dst, Register count) {
-  if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
+  if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahStoreValEnqueueBarrier || ShenandoahLoadRefBarrier) {
 
     Label done;
 
@@ -52,7 +52,7 @@
     // Is GC active?
     Address gc_state(rthread, in_bytes(JavaThread::gc_state_offset()));
     __ ldrb(rscratch1, gc_state);
-    if (dest_uninitialized) {
+    if (ShenandoahSATBBarrier && dest_uninitialized) {
       __ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);
     } else {
       __ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);
diff --git a/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp b/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
--- a/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
+++ b/src/cpu/x86/vm/shenandoahBarrierSetAssembler_x86.cpp
@@ -43,7 +43,7 @@
 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, bool dest_uninitialized,
                                                        Register src, Register dst, Register count) {
 
-  if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
+  if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahStoreValEnqueueBarrier || ShenandoahLoadRefBarrier) {
 #ifdef _LP64
     Register thread = r15_thread;
 #else
@@ -69,9 +69,11 @@
 
     // Avoid runtime call when not active.
     Address gc_state(thread, in_bytes(JavaThread::gc_state_offset()));
-    int flags = ShenandoahHeap::HAS_FORWARDED;
-    if (!dest_uninitialized) {
-      flags |= ShenandoahHeap::MARKING;
+    int flags;
+    if (ShenandoahSATBBarrier && dest_uninitialized) {
+      flags = ShenandoahHeap::HAS_FORWARDED;
+    } else {
+      flags = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING;
     }
     __ testb(gc_state, flags);
     __ jcc(Assembler::zero, done);
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
@@ -44,7 +44,7 @@
 
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
@@ -43,7 +43,7 @@
 
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
@@ -36,7 +36,7 @@
 
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
@@ -212,7 +212,7 @@
 }
 
 void ShenandoahBarrierSet::storeval_barrier(oop obj) {
-  if (ShenandoahStoreValEnqueueBarrier && !oopDesc::is_null(obj)) {
+  if (ShenandoahStoreValEnqueueBarrier && !oopDesc::is_null(obj) && _heap->is_concurrent_mark_in_progress()) {
     enqueue(obj);
   }
 }
@@ -271,5 +271,7 @@
 }
 
 void ShenandoahBarrierSet::clone_barrier_runtime(oop src) {
-  clone_barrier(src);
+  if (_heap->has_forwarded_objects() || (ShenandoahStoreValEnqueueBarrier && _heap->is_concurrent_mark_in_progress())) {
+    clone_barrier(src);
+  }
 }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
@@ -117,12 +117,16 @@
 
 private:
   template <class T>
-  inline void arraycopy_marking(T* ary, size_t count);
+  inline void arraycopy_marking(T* src, T* dst, size_t count);
   template <class T>
   inline void arraycopy_evacuation(T* src, size_t count);
   template <class T>
   inline void arraycopy_update(T* src, size_t count);
 
+  inline void clone_marking(oop src);
+  inline void clone_evacuation(oop src);
+  inline void clone_update(oop src);
+
   template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
   inline void arraycopy_work(T* src, size_t count);
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
@@ -80,7 +80,7 @@
   }
   int gc_state = _heap->gc_state();
   if ((gc_state & ShenandoahHeap::MARKING) != 0) {
-    arraycopy_marking(dst, count);
+    arraycopy_marking(src, dst, count);
   } else if ((gc_state & ShenandoahHeap::EVACUATION) != 0) {
     arraycopy_evacuation(src, count);
   } else if ((gc_state & ShenandoahHeap::UPDATEREFS) != 0) {
@@ -89,8 +89,9 @@
 }
 
 template <class T>
-void ShenandoahBarrierSet::arraycopy_marking(T* array, size_t count) {
+void ShenandoahBarrierSet::arraycopy_marking(T* src, T* dst, size_t count) {
   assert(_heap->is_concurrent_mark_in_progress(), "only during marking");
+  T* array = ShenandoahSATBBarrier ? dst : src;
   if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(array))) {
     arraycopy_work<T, false, false, true>(array, count);
   }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp
@@ -31,7 +31,7 @@
 #include "memory/iterator.hpp"
 #include "oops/oop.inline.hpp"
 
-template <bool EVAC, bool ENQUEUE>
+template <bool HAS_FWD, bool EVAC, bool ENQUEUE>
 class ShenandoahUpdateRefsForOopClosure: public ExtendedOopClosure {
 private:
   ShenandoahHeap* const _heap;
@@ -44,18 +44,18 @@
     T o = oopDesc::load_heap_oop(p);
     if (!oopDesc::is_null(o)) {
       oop obj = oopDesc::decode_heap_oop_not_null(o);
-      if (_cset->is_in(obj)) {
+      if (HAS_FWD && _cset->is_in(obj)) {
         oop fwd = _bs->resolve_forwarded_not_null(obj);
         if (EVAC && obj == fwd) {
           fwd = _heap->evacuate_object(obj, _thread);
         }
-        if (ENQUEUE) {
-          _bs->enqueue(fwd);
-        }
         assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
         ShenandoahHeap::cas_oop(fwd, p, o);
+        obj = fwd;
       }
-
+      if (ENQUEUE) {
+        _bs->enqueue(obj);
+      }
     }
   }
 public:
@@ -70,25 +70,44 @@
   virtual void do_oop(narrowOop* p) { do_oop_work(p); }
 };
 
-void ShenandoahBarrierSet::clone_barrier(oop obj) {
-  assert(ShenandoahCloneBarrier, "only get here with clone barriers enabled");
-  if (!_heap->has_forwarded_objects()) return;
-
-  // This is called for cloning an object (see jvm.cpp) after the clone
-  // has been made. We are not interested in any 'previous value' because
-  // it would be NULL in any case. But we *are* interested in any oop*
-  // that potentially need to be updated.
+void ShenandoahBarrierSet::clone_marking(oop obj) {
+  assert(_heap->is_concurrent_mark_in_progress(), "only during marking");
+  assert(ShenandoahStoreValEnqueueBarrier, "only with incremental-update");
+  if (!_heap->marking_context()->allocated_after_mark_start(obj)) {
+    ShenandoahUpdateRefsForOopClosure</* has_fwd = */ false, /* evac = */ false, /* enqueue */ true> cl;
+    obj->oop_iterate(&cl);
+  }
+}
  
-  shenandoah_assert_correct(NULL, obj);
-  if (!need_bulk_update(cast_from_oop<HeapWord*>(obj))) return;
-  if (_heap->is_evacuation_in_progress()) {
-    ShenandoahEvacOOMScope evac_scope;
-    ShenandoahUpdateRefsForOopClosure</* evac = */ true, /* enqueue */ false> cl;
-    obj->oop_iterate(&cl);
-  } else {
-    ShenandoahUpdateRefsForOopClosure</* evac = */ false, /* enqueue */ false> cl;
+void ShenandoahBarrierSet::clone_evacuation(oop obj) {
+  assert(_heap->is_evacuation_in_progress(), "only during evacuation");
+  if (need_bulk_update(cast_from_oop<HeapWord*>(obj))) {
+    ShenandoahEvacOOMScope oom_evac_scope;
+    ShenandoahUpdateRefsForOopClosure</* has_fwd = */ true, /* evac = */ true, /* enqueue */ false> cl;
+     obj->oop_iterate(&cl);
+  }
+}
+
+void ShenandoahBarrierSet::clone_update(oop obj) {
+  assert(_heap->is_update_refs_in_progress(), "only during update-refs");
+  if (need_bulk_update(cast_from_oop<HeapWord*>(obj))) {
+    ShenandoahUpdateRefsForOopClosure</* has_fwd = */ true, /* evac = */ false, /* enqueue */ false> cl;
     obj->oop_iterate(&cl);
   }
 }
 
+void ShenandoahBarrierSet::clone_barrier(oop obj) {
+  assert(ShenandoahCloneBarrier, "only get here with clone barriers enabled");
+  shenandoah_assert_correct(NULL, obj);
+
+  int gc_state = _heap->gc_state();
+  if ((gc_state & ShenandoahHeap::MARKING) != 0) {
+    clone_marking(obj);
+  } else if ((gc_state & ShenandoahHeap::EVACUATION) != 0) {
+    clone_evacuation(obj);
+  } else {
+    clone_update(obj);
+  }
+}
+
 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHBARRIERSETCLONE_INLINE_HPP
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp
@@ -218,12 +218,13 @@
 class ShenandoahSATBAndRemarkCodeRootsThreadsClosure : public ThreadClosure {
 private:
   ShenandoahSATBBufferClosure* _satb_cl;
-  MarkingCodeBlobClosure*              _code_cl;
+  OopClosure*            const _cl;
+  MarkingCodeBlobClosure*      _code_cl;
   int _thread_parity;
 
 public:
-  ShenandoahSATBAndRemarkCodeRootsThreadsClosure(ShenandoahSATBBufferClosure* satb_cl, MarkingCodeBlobClosure* code_cl) :
-    _satb_cl(satb_cl), _code_cl(code_cl),
+  ShenandoahSATBAndRemarkCodeRootsThreadsClosure(ShenandoahSATBBufferClosure* satb_cl, OopClosure* cl, MarkingCodeBlobClosure* code_cl) :
+    _satb_cl(satb_cl), _cl(cl), _code_cl(code_cl),
     _thread_parity(SharedHeap::heap()->strong_roots_parity()) {}
 
   void do_thread(Thread* thread) {
@@ -231,7 +232,10 @@
       if (thread->claim_oops_do(true, _thread_parity)) {
         JavaThread* jt = (JavaThread*)thread;
         jt->satb_mark_queue().apply_closure_and_empty(_satb_cl);
-        if (_code_cl != NULL) {
+        if (_cl != NULL) {
+          ResourceMark rm;
+          jt->oops_do(_cl, NULL, _code_cl);
+        } else if (_code_cl != NULL) {
           // In theory it should not be neccessary to explicitly walk the nmethods to find roots for concurrent marking
           // however the liveness of oops reachable from nmethods have very complex lifecycles:
           // * Alive if on the stack of an executing method
@@ -285,20 +289,20 @@
       ShenandoahSATBBufferClosure cl(q, dq);
       SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
       while (satb_mq_set.apply_closure_to_completed_buffer(&cl));
-      if (heap->unload_classes()) {
-        if (heap->has_forwarded_objects()) {
-          ShenandoahMarkResolveRefsClosure resolve_mark_cl(q, rp);
-          MarkingCodeBlobClosure blobsCl(&resolve_mark_cl, !CodeBlobToOopClosure::FixRelocations);
-          ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, &blobsCl);
-          Threads::threads_do(&tc);
-        } else {
-          ShenandoahMarkRefsClosure mark_cl(q, rp);
-          MarkingCodeBlobClosure blobsCl(&mark_cl, !CodeBlobToOopClosure::FixRelocations);
-          ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, &blobsCl);
-          Threads::threads_do(&tc);
-        }
+      bool do_nmethods = heap->unload_classes();
+      if (heap->has_forwarded_objects()) {
+        ShenandoahMarkResolveRefsClosure resolve_mark_cl(q, rp);
+        MarkingCodeBlobClosure blobsCl(&resolve_mark_cl, !CodeBlobToOopClosure::FixRelocations);
+        ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl,
+                                                          ShenandoahStoreValEnqueueBarrier ? &resolve_mark_cl : NULL,
+                                                          do_nmethods ? &blobsCl : NULL);
+        Threads::threads_do(&tc);
       } else {
-        ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl, NULL);
+        ShenandoahMarkRefsClosure mark_cl(q, rp);
+        MarkingCodeBlobClosure blobsCl(&mark_cl, !CodeBlobToOopClosure::FixRelocations);
+        ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl,
+                                                          ShenandoahStoreValEnqueueBarrier ? &mark_cl : NULL,
+                                                          do_nmethods ? &blobsCl : NULL);
         Threads::threads_do(&tc);
       }
     }
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp
@@ -40,6 +40,7 @@
 #include "gc_implementation/shenandoah/shenandoahHeapRegion.hpp"
 #include "gc_implementation/shenandoah/shenandoahHeapRegionSet.hpp"
 #include "gc_implementation/shenandoah/shenandoahHeuristics.hpp"
+#include "gc_implementation/shenandoah/shenandoahIUMode.hpp"
 #include "gc_implementation/shenandoah/shenandoahMarkCompact.hpp"
 #include "gc_implementation/shenandoah/shenandoahMarkingContext.inline.hpp"
 #include "gc_implementation/shenandoah/shenandoahMonitoringSupport.hpp"
@@ -388,6 +389,8 @@
   if (ShenandoahGCMode != NULL) {
     if (strcmp(ShenandoahGCMode, "normal") == 0) {
       _gc_mode = new ShenandoahNormalMode();
+    } else if (strcmp(ShenandoahGCMode, "iu") == 0) {
+      _gc_mode = new ShenandoahIUMode();
     } else if (strcmp(ShenandoahGCMode, "passive") == 0) {
       _gc_mode = new ShenandoahPassiveMode();
     } else {
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
@@ -57,7 +57,7 @@
 
 #define SHENANDOAH_CHECK_FLAG_SET(name)                                     \
   do {                                                                      \
-    if (!name) {                                                            \
+    if (!(name)) {                                                          \
       err_msg message("Heuristics needs -XX:+" #name " to work correctly"); \
       vm_exit_during_initialization("Error", message);                      \
     }                                                                       \
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp
new file mode 100644
--- /dev/null
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/shenandoah/shenandoahIUMode.hpp"
+#include "gc_implementation/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp"
+#include "gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp"
+#include "gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.hpp"
+#include "gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.hpp"
+#include "gc_implementation/shenandoah/shenandoahLogging.hpp"
+
+void ShenandoahIUMode::initialize_flags() const {
+  FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, true);
+  FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false);
+
+  SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent);
+  SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent);
+
+  // Final configuration checks
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValEnqueueBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
+  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
+}
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.hpp
new file mode 100644
--- /dev/null
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHIUMODE_HPP
+#define SHARE_GC_SHENANDOAH_SHENANDOAHIUMODE_HPP
+
+#include "gc_implementation/shenandoah/shenandoahNormalMode.hpp"
+
+class ShenandoahHeuristics;
+
+class ShenandoahIUMode : public ShenandoahNormalMode {
+public:
+  virtual void initialize_flags() const;
+
+  virtual const char* name()     { return "Incremental-Update"; }
+  virtual bool is_diagnostic()   { return false; }
+  virtual bool is_experimental() { return true; }
+};
+
+#endif // SHARE_GC_SHENANDOAH_SHENANDOAHIUMODE_HPP
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
@@ -65,5 +65,5 @@
 JRT_LEAF(void, ShenandoahRuntime::shenandoah_clone_barrier(oopDesc* src))
   oop s = oop(src);
   shenandoah_assert_correct(NULL, s);
-  ShenandoahBarrierSet::barrier_set()->clone_barrier(s);
+  ShenandoahBarrierSet::barrier_set()->clone_barrier_runtime(s);
 JRT_END
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.cpp
@@ -827,8 +827,8 @@
   }
 }
 
-void ShenandoahBarrierC2Support::test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl,
-                                                  PhaseIdealLoop* phase) {
+void ShenandoahBarrierC2Support::test_heap_state(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl,
+                                                 PhaseIdealLoop* phase, int flags) {
   IdealLoopTree* loop = phase->get_loop(ctrl);
   Node* thread = new (phase->C) ThreadLocalNode();
   phase->register_new_node(thread, ctrl);
@@ -842,7 +842,7 @@
 
   Node* gc_state = new (phase->C) LoadBNode(ctrl, raw_mem, gc_state_addr, gc_state_adr_type, TypeInt::BYTE, MemNode::unordered);
   phase->register_new_node(gc_state, ctrl);
-  Node* heap_stable_and = new (phase->C) AndINode(gc_state, phase->igvn().intcon(ShenandoahHeap::HAS_FORWARDED));
+  Node* heap_stable_and = new (phase->C) AndINode(gc_state, phase->igvn().intcon(flags));
   phase->register_new_node(heap_stable_and, ctrl);
   Node* heap_stable_cmp = new (phase->C) CmpINode(heap_stable_and, phase->igvn().zerocon(T_INT));
   phase->register_new_node(heap_stable_cmp, ctrl);
@@ -856,7 +856,7 @@
   ctrl = new (phase->C) IfTrueNode(heap_stable_iff);
   phase->register_control(ctrl, loop, heap_stable_iff);
 
-  assert(is_heap_stable_test(heap_stable_iff), "Should match the shape");
+  assert(is_heap_state_test(heap_stable_iff, flags), "Should match the shape");
 }
 
 void ShenandoahBarrierC2Support::test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase) {
@@ -1364,7 +1364,7 @@
     Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM);
 
     // Stable path.
-    test_heap_stable(ctrl, raw_mem, heap_stable_ctrl, phase);
+    test_heap_state(ctrl, raw_mem, heap_stable_ctrl, phase, ShenandoahHeap::HAS_FORWARDED);
     IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If();
 
     // Heap stable case
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahSupport.hpp
@@ -61,8 +61,8 @@
   static Node* find_bottom_mem(Node* ctrl, PhaseIdealLoop* phase);
   static void follow_barrier_uses(Node* n, Node* ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase);
   static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase);
-  static void test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl,
-                               PhaseIdealLoop* phase);
+  static void test_heap_state(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl,
+                              PhaseIdealLoop* phase, int flags);
   static void call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase);
   static Node* clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase);
   static void fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, Unique_Node_List& uses,
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoah_globals.hpp
@@ -62,6 +62,7 @@
           "GC mode to use.  Among other things, this defines which "        \
           "barriers are in in use. Possible values are:"                    \
           " normal - default concurrent GC (three pass mark-evac-update);"  \
+          " iu - incremental-update concurrent GC (three pass mark-evac-update);"  \
           " passive - stop the world GC only (either degenerated or full)") \
                                                                             \
   product(ccstr, ShenandoahGCHeuristics, "adaptive",                        \
diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
--- a/src/share/vm/prims/jvm.cpp
+++ b/src/share/vm/prims/jvm.cpp
@@ -648,7 +648,7 @@
 
 #if INCLUDE_ALL_GCS
   if (UseShenandoahGC && ShenandoahCloneBarrier) {
-    ShenandoahBarrierSet::barrier_set()->clone_barrier(obj());
+    ShenandoahBarrierSet::barrier_set()->clone_barrier_runtime(obj());
   }
 #endif
 
diff --git a/test/gc/shenandoah/TestAllocHumongousFragment.java b/test/gc/shenandoah/TestAllocHumongousFragment.java
--- a/test/gc/shenandoah/TestAllocHumongousFragment.java
+++ b/test/gc/shenandoah/TestAllocHumongousFragment.java
@@ -90,6 +90,41 @@
  *      TestAllocHumongousFragment
  */
 
+/*
+ * @test TestAllocHumongousFragment
+ * @summary Make sure Shenandoah can recover from humongous allocation fragmentation
+ * @key gc
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify
+ *      TestAllocHumongousFragment
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify
+ *      TestAllocHumongousFragment
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestAllocHumongousFragment
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestAllocHumongousFragment
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestAllocHumongousFragment
+ *
+ * @run main/othervm -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g -XX:ShenandoahTargetNumRegions=2048
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestAllocHumongousFragment
+ */
+
 import java.util.*;
 import java.util.concurrent.*;
 
diff --git a/test/gc/shenandoah/TestAllocIntArrays.java b/test/gc/shenandoah/TestAllocIntArrays.java
--- a/test/gc/shenandoah/TestAllocIntArrays.java
+++ b/test/gc/shenandoah/TestAllocIntArrays.java
@@ -99,6 +99,45 @@
  *      TestAllocIntArrays
  */
 
+/*
+ * @test TestAllocIntArrays
+ * @summary Acceptance tests: collector can withstand allocation
+ * @key gc
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestAllocIntArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestAllocIntArrays
+ */
+
 import java.util.Random;
 
 public class TestAllocIntArrays {
diff --git a/test/gc/shenandoah/TestAllocObjectArrays.java b/test/gc/shenandoah/TestAllocObjectArrays.java
--- a/test/gc/shenandoah/TestAllocObjectArrays.java
+++ b/test/gc/shenandoah/TestAllocObjectArrays.java
@@ -98,6 +98,45 @@
  *      TestAllocObjectArrays
  */
 
+/*
+ * @test TestAllocObjectArrays
+ * @summary Acceptance tests: collector can withstand allocation
+ * @key gc
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestAllocObjectArrays
+ *
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestAllocObjectArrays
+ */
+
 import java.util.Random;
 
 public class TestAllocObjectArrays {
diff --git a/test/gc/shenandoah/TestAllocObjects.java b/test/gc/shenandoah/TestAllocObjects.java
--- a/test/gc/shenandoah/TestAllocObjects.java
+++ b/test/gc/shenandoah/TestAllocObjects.java
@@ -94,6 +94,45 @@
  *      TestAllocObjects
  */
 
+/*
+ * @test TestAllocObjects
+ * @summary Acceptance tests: collector can withstand allocation
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot -XX:+ShenandoahVerify
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot -XX:+ShenandoahVerify
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestAllocObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestAllocObjects
+ */
+
 import java.util.Random;
 
 public class TestAllocObjects {
diff --git a/test/gc/shenandoah/TestGCThreadGroups.java b/test/gc/shenandoah/TestGCThreadGroups.java
--- a/test/gc/shenandoah/TestGCThreadGroups.java
+++ b/test/gc/shenandoah/TestGCThreadGroups.java
@@ -81,6 +81,24 @@
  *      TestGCThreadGroups
  */
 
+/**
+ * @test TestGCThreadGroups
+ * @summary Test Shenandoah GC uses concurrent/parallel threads correctly
+ * @key gc
+ *
+ * @run main/othervm -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:ConcGCThreads=2 -XX:ParallelGCThreads=4
+ *      -Dtarget=1000
+ *      TestGCThreadGroups
+ *
+ * @run main/othervm -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:ConcGCThreads=2 -XX:ParallelGCThreads=4
+ *      -Dtarget=1000
+ *      TestGCThreadGroups
+*/
+
 public class TestGCThreadGroups {
 
     static final long TARGET_MB = Long.getLong("target", 10_000); // 10 Gb allocation, around 1K cycles to handle
diff --git a/test/gc/shenandoah/TestHeapUncommit.java b/test/gc/shenandoah/TestHeapUncommit.java
--- a/test/gc/shenandoah/TestHeapUncommit.java
+++ b/test/gc/shenandoah/TestHeapUncommit.java
@@ -81,6 +81,25 @@
 
 /*
  * @test TestHeapUncommit
+ * @summary Acceptance tests: collector can withstand allocation
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ShenandoahUncommit -XX:ShenandoahUncommitDelay=0
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestHeapUncommit
+ *
+ * @run main/othervm -Xmx1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ShenandoahUncommit -XX:ShenandoahUncommitDelay=0
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestHeapUncommit
+ *
+ * @run main/othervm -Xmx1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ShenandoahUncommit -XX:ShenandoahUncommitDelay=0
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestHeapUncommit
+ */
+
+/*
+ * @test TestHeapUncommit
  * @key gc
  * @requires (vm.bits == "64")
  *
diff --git a/test/gc/shenandoah/TestLotsOfCycles.java b/test/gc/shenandoah/TestLotsOfCycles.java
--- a/test/gc/shenandoah/TestLotsOfCycles.java
+++ b/test/gc/shenandoah/TestLotsOfCycles.java
@@ -75,6 +75,33 @@
  *     TestLotsOfCycles
  */
 
+/*
+ * @test TestLotsOfCycles
+ * @key gc
+ *
+ * @run main/othervm/timeout=480 -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      -Dtarget=1000
+ *      TestLotsOfCycles
+ *
+ * @run main/othervm/timeout=480 -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      -Dtarget=1000
+ *      TestLotsOfCycles
+ *
+ * @run main/othervm/timeout=480 -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -Dtarget=1000
+ *      TestLotsOfCycles
+ *
+ * @run main/othervm/timeout=480 -Xmx16m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -Dtarget=10000
+ *      TestLotsOfCycles
+ */
+
 public class TestLotsOfCycles {
 
     static final long TARGET_MB = Long.getLong("target", 10_000); // 10 Gb allocation, around 1K cycles to handle
diff --git a/test/gc/shenandoah/TestPeriodicGC.java b/test/gc/shenandoah/TestPeriodicGC.java
--- a/test/gc/shenandoah/TestPeriodicGC.java
+++ b/test/gc/shenandoah/TestPeriodicGC.java
@@ -96,6 +96,36 @@
             );
         }
 
+        testWith("Zero interval with iu mode",
+                 false,
+                 "-verbose:gc",
+                 "-XX:+UnlockDiagnosticVMOptions",
+                 "-XX:+UnlockExperimentalVMOptions",
+                 "-XX:+UseShenandoahGC",
+                 "-XX:ShenandoahGCMode=iu",
+                 "-XX:ShenandoahGuaranteedGCInterval=0"
+        );
+
+        testWith("Short interval with iu mode",
+                 true,
+                 "-verbose:gc",
+                 "-XX:+UnlockDiagnosticVMOptions",
+                 "-XX:+UnlockExperimentalVMOptions",
+                 "-XX:+UseShenandoahGC",
+                 "-XX:ShenandoahGCMode=iu",
+                 "-XX:ShenandoahGuaranteedGCInterval=1000"
+        );
+
+        testWith("Long interval with iu mode",
+                 false,
+                 "-verbose:gc",
+                 "-XX:+UnlockDiagnosticVMOptions",
+                 "-XX:+UnlockExperimentalVMOptions",
+                 "-XX:+UseShenandoahGC",
+                 "-XX:ShenandoahGCMode=iu",
+                 "-XX:ShenandoahGuaranteedGCInterval=100000" // deliberately too long
+        );
+
         testWith("Short interval with aggressive",
                  false,
                  "-verbose:gc",
diff --git a/test/gc/shenandoah/TestRefprocSanity.java b/test/gc/shenandoah/TestRefprocSanity.java
--- a/test/gc/shenandoah/TestRefprocSanity.java
+++ b/test/gc/shenandoah/TestRefprocSanity.java
@@ -40,6 +40,25 @@
  *      TestRefprocSanity
  */
 
+/*
+ * @test TestRefprocSanity
+ * @summary Test that null references/referents work fine
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestRefprocSanity
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestRefprocSanity
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestRefprocSanity
+ */
+
 import java.lang.ref.*;
 
 public class TestRefprocSanity {
diff --git a/test/gc/shenandoah/TestRegionSampling.java b/test/gc/shenandoah/TestRegionSampling.java
--- a/test/gc/shenandoah/TestRegionSampling.java
+++ b/test/gc/shenandoah/TestRegionSampling.java
@@ -57,6 +57,19 @@
  *      TestRegionSampling
  */
 
+/*
+ * @test TestRegionSampling
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ShenandoahRegionSampling
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestRegionSampling
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ShenandoahRegionSampling
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestRegionSampling
+ *
+ */
+
 public class TestRegionSampling {
 
     static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation
diff --git a/test/gc/shenandoah/TestRetainObjects.java b/test/gc/shenandoah/TestRetainObjects.java
--- a/test/gc/shenandoah/TestRetainObjects.java
+++ b/test/gc/shenandoah/TestRetainObjects.java
@@ -89,6 +89,35 @@
  *      TestRetainObjects
  */
 
+/*
+ * @test TestRetainObjects
+ * @summary Acceptance tests: collector can deal with retained objects
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestRetainObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestRetainObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestRetainObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestRetainObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestRetainObjects
+ */
+
 public class TestRetainObjects {
 
     static final int COUNT = 10_000_000;
diff --git a/test/gc/shenandoah/TestSieveObjects.java b/test/gc/shenandoah/TestSieveObjects.java
--- a/test/gc/shenandoah/TestSieveObjects.java
+++ b/test/gc/shenandoah/TestSieveObjects.java
@@ -89,6 +89,35 @@
  *      TestSieveObjects
  */
 
+/*
+ * @test TestSieveObjects
+ * @summary Acceptance tests: collector can deal with retained objects
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      TestSieveObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahAllocFailureALot
+ *      TestSieveObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestSieveObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestSieveObjects
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestSieveObjects
+ */
+
 import java.util.concurrent.ThreadLocalRandom;
 
 public class TestSieveObjects {
diff --git a/test/gc/shenandoah/TestStringDedup.java b/test/gc/shenandoah/TestStringDedup.java
--- a/test/gc/shenandoah/TestStringDedup.java
+++ b/test/gc/shenandoah/TestStringDedup.java
@@ -58,6 +58,20 @@
  *      TestStringDedup
  */
 
+/*
+ * @test TestStringDedup
+ * @summary Test Shenandoah string deduplication implementation
+ * @key gc
+ *
+ * @run main/othervm -Xmx256m -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestStringDedup
+ *
+ * @run main/othervm -Xmx256m -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestStringDedup
+ */
+
 import java.lang.reflect.*;
 import java.util.*;
 
diff --git a/test/gc/shenandoah/TestStringDedupStress.java b/test/gc/shenandoah/TestStringDedupStress.java
--- a/test/gc/shenandoah/TestStringDedupStress.java
+++ b/test/gc/shenandoah/TestStringDedupStress.java
@@ -63,6 +63,33 @@
  *      TestStringDedupStress
  */
 
+ /*
+ * @test TestStringDedupStress
+ * @summary Test Shenandoah string deduplication implementation
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestStringDedupStress
+ *
+ * @run main/othervm -Xmx1g -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -DtargetStrings=2000000
+ *      TestStringDedupStress
+ *
+ * @run main/othervm -Xmx1g -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      -DtargetStrings=2000000
+ *      TestStringDedupStress
+ *
+ * @run main/othervm -Xmx1g -verbose:gc -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseStringDeduplication
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahOOMDuringEvacALot
+ *      -DtargetStrings=2000000
+ *      TestStringDedupStress
+ */
+
 import java.lang.management.*;
 import java.lang.reflect.*;
 import java.util.*;
diff --git a/test/gc/shenandoah/TestStringInternCleanup.java b/test/gc/shenandoah/TestStringInternCleanup.java
--- a/test/gc/shenandoah/TestStringInternCleanup.java
+++ b/test/gc/shenandoah/TestStringInternCleanup.java
@@ -74,6 +74,26 @@
  *      TestStringInternCleanup
  */
 
+/*
+ * @test TestStringInternCleanup
+ * @summary Check that Shenandoah cleans up interned strings
+ * @key gc
+ *
+ * @run main/othervm -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ClassUnloadingWithConcurrentMark
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify
+ *      TestStringInternCleanup
+ *
+ * @run main/othervm -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ClassUnloadingWithConcurrentMark
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -XX:+ShenandoahVerify
+ *      TestStringInternCleanup
+ *
+ * @run main/othervm -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+ClassUnloadingWithConcurrentMark
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestStringInternCleanup
+ */
+
 public class TestStringInternCleanup {
 
     static final int COUNT = 1_000_000;
diff --git a/test/gc/shenandoah/TestVerifyJCStress.java b/test/gc/shenandoah/TestVerifyJCStress.java
--- a/test/gc/shenandoah/TestVerifyJCStress.java
+++ b/test/gc/shenandoah/TestVerifyJCStress.java
@@ -53,6 +53,17 @@
  *      TestVerifyJCStress
  */
 
+/*
+ * @test TestVerifyJCStress
+ * @summary Tests that we pass at least one jcstress-like test with all verification turned on
+ * @key gc
+ *
+ * @run main/othervm -Xmx1g -Xms1g -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -XX:+ShenandoahVerify -XX:+IgnoreUnrecognizedVMOptions -XX:+ShenandoahVerifyOptoBarriers
+ *      TestVerifyJCStress
+ */
+
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.locks.*;
diff --git a/test/gc/shenandoah/TestWrongArrayMember.java b/test/gc/shenandoah/TestWrongArrayMember.java
--- a/test/gc/shenandoah/TestWrongArrayMember.java
+++ b/test/gc/shenandoah/TestWrongArrayMember.java
@@ -25,7 +25,8 @@
  * @test TestWrongArrayMember
  * @key gc
  *
- * @run main/othervm -Xmx128m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC                                      TestWrongArrayMember
+ * @run main/othervm -Xmx128m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC                         TestWrongArrayMember
+ * @run main/othervm -Xmx128m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu TestWrongArrayMember
  */
 
 public class TestWrongArrayMember {
diff --git a/test/gc/shenandoah/mxbeans/TestChurnNotifications.java b/test/gc/shenandoah/mxbeans/TestChurnNotifications.java
--- a/test/gc/shenandoah/mxbeans/TestChurnNotifications.java
+++ b/test/gc/shenandoah/mxbeans/TestChurnNotifications.java
@@ -62,6 +62,21 @@
  *      TestChurnNotifications
  */
 
+/*
+ * @test TestChurnNotifications
+ * @summary Check that MX notifications are reported for all cycles
+ *
+ * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      -Dprecise=false
+ *      TestChurnNotifications
+ *
+ * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      -Dprecise=false
+ *      TestChurnNotifications
+ */
+
 import java.util.*;
 import java.util.concurrent.atomic.*;
 import javax.management.*;
diff --git a/test/gc/shenandoah/mxbeans/TestPauseNotifications.java b/test/gc/shenandoah/mxbeans/TestPauseNotifications.java
--- a/test/gc/shenandoah/mxbeans/TestPauseNotifications.java
+++ b/test/gc/shenandoah/mxbeans/TestPauseNotifications.java
@@ -59,6 +59,20 @@
  *      TestPauseNotifications
  */
 
+/*
+ * @test TestPauseNotifications
+ * @summary Check that MX notifications are reported for all cycles
+ * @key gc
+ *
+ * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive
+ *      TestPauseNotifications
+ *
+ * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions
+ *      -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu
+ *      TestPauseNotifications
+ */
+
 import java.util.*;
 import java.util.concurrent.atomic.*;
 import javax.management.*;
diff --git a/test/gc/shenandoah/oom/TestClassLoaderLeak.java b/test/gc/shenandoah/oom/TestClassLoaderLeak.java
--- a/test/gc/shenandoah/oom/TestClassLoaderLeak.java
+++ b/test/gc/shenandoah/oom/TestClassLoaderLeak.java
@@ -123,8 +123,9 @@
         }
 
         String[][][] modeHeuristics = new String[][][] {
-             {{"normal"},    {"adaptive", "compact", "static", "aggressive"}},
-             {{"passive"},   {"passive"}}
+             {{"normal"},  {"adaptive", "compact", "static", "aggressive"}},
+             {{"iu"},      {"adaptive", "aggressive"}},
+             {{"passive"}, {"passive"}}
         };
 
         for (String[][] mh : modeHeuristics) {
diff --git a/test/gc/shenandoah/options/TestExplicitGC.java b/test/gc/shenandoah/options/TestExplicitGC.java
--- a/test/gc/shenandoah/options/TestExplicitGC.java
+++ b/test/gc/shenandoah/options/TestExplicitGC.java
@@ -122,5 +122,23 @@
                 output.shouldNotContain(p);
             }
         }
+
+        {
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:+UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    "-verbose:gc",
+                    "-XX:+ExplicitGCInvokesConcurrent",
+                    "-XX:ShenandoahGCMode=iu",
+                    TestExplicitGC.class.getName(),
+                    "test");
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            for (String p : full) {
+                output.shouldNotContain(p);
+            }
+            for (String p : concNormal) {
+                output.shouldContain(p);
+            }
+         }
     }
 }
diff --git a/test/gc/shenandoah/options/TestHeuristicsUnlock.java b/test/gc/shenandoah/options/TestHeuristicsUnlock.java
--- a/test/gc/shenandoah/options/TestHeuristicsUnlock.java
+++ b/test/gc/shenandoah/options/TestHeuristicsUnlock.java
@@ -45,6 +45,8 @@
         testWith("-XX:ShenandoahGCHeuristics=static", Mode.PRODUCT);
         testWith("-XX:ShenandoahGCHeuristics=compact", Mode.PRODUCT);
 
+        testWith("-XX:ShenandoahGCMode=iu", Mode.EXPERIMENTAL);
+
         testWith("-XX:ShenandoahGCHeuristics=aggressive", Mode.DIAGNOSTIC);
         testWith("-XX:ShenandoahGCMode=passive", Mode.DIAGNOSTIC);
     }
diff --git a/test/gc/shenandoah/options/TestSelectiveBarrierFlags.java b/test/gc/shenandoah/options/TestSelectiveBarrierFlags.java
--- a/test/gc/shenandoah/options/TestSelectiveBarrierFlags.java
+++ b/test/gc/shenandoah/options/TestSelectiveBarrierFlags.java
@@ -40,8 +40,8 @@
 
     public static void main(String[] args) throws Exception {
         String[][] opts = {
-                new String[]{ "ShenandoahSATBBarrier" },
                 new String[]{ "ShenandoahLoadRefBarrier" },
+                new String[] { "ShenandoahSATBBarrier", "ShenandoahStoreValEnqueueBarrier" },
                 new String[]{ "ShenandoahCASBarrier" },
                 new String[]{ "ShenandoahCloneBarrier" },
         };
diff --git a/test/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
--- a/test/gc/shenandoah/options/TestWrongBarrierDisable.java
+++ b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
@@ -37,16 +37,23 @@
     public static void main(String[] args) throws Exception {
         String[] concurrent = {
                 "ShenandoahLoadRefBarrier",
+                "ShenandoahSATBBarrier",
                 "ShenandoahCASBarrier",
                 "ShenandoahCloneBarrier",
-                "ShenandoahSATBBarrier",
+        };
+        String[] iu = {
+                "ShenandoahLoadRefBarrier",
+                "ShenandoahCASBarrier",
+                "ShenandoahCloneBarrier",
         };
 
         shouldFailAll("-XX:ShenandoahGCHeuristics=adaptive",   concurrent);
         shouldFailAll("-XX:ShenandoahGCHeuristics=static",     concurrent);
         shouldFailAll("-XX:ShenandoahGCHeuristics=compact",    concurrent);
         shouldFailAll("-XX:ShenandoahGCHeuristics=aggressive", concurrent);
+        shouldFailAll("-XX:ShenandoahGCMode=iu",               iu);
         shouldPassAll("-XX:ShenandoahGCMode=passive",          concurrent);
+        shouldPassAll("-XX:ShenandoahGCMode=passive",          iu);
     }
 
     private static void shouldFailAll(String h, String[] barriers) throws Exception {
# HG changeset patch
# User shade
# Date 1586258326 -7200
#      Tue Apr 07 13:18:46 2020 +0200
# Node ID fbbd9bde2c7858883a2edc3aaa5fee1328ff365d
# Parent  a222813e5654b4a6809ad0233238300f862565c2
[backport] 8242271: Shenandoah: add test to verify GC mode unlock
Reviewed-by: rkennke

diff --git a/test/gc/shenandoah/options/TestModeUnlock.java b/test/gc/shenandoah/options/TestModeUnlock.java
new file mode 100644
--- /dev/null
+++ b/test/gc/shenandoah/options/TestModeUnlock.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test TestModeUnlock
+ * @summary Test that Shenandoah modes are unlocked properly
+ * @key gc
+ * @library /testlibrary
+ * @run driver TestModeUnlock
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestModeUnlock {
+
+    enum Mode {
+        PRODUCT,
+        DIAGNOSTIC,
+        EXPERIMENTAL,
+    }
+
+    public static void main(String[] args) throws Exception {
+        testWith("-XX:ShenandoahGCMode=normal",  Mode.PRODUCT);
+        testWith("-XX:ShenandoahGCMode=iu",      Mode.EXPERIMENTAL);
+        testWith("-XX:ShenandoahGCMode=passive", Mode.DIAGNOSTIC);
+    }
+
+    private static void testWith(String h, Mode mode) throws Exception {
+        if (false) { // When ShenandoahGC is experimental flag, this makes no sense to test
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:-UnlockDiagnosticVMOptions",
+                    "-XX:-UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    h,
+                    "-version"
+            );
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            switch (mode) {
+                case PRODUCT:
+                    output.shouldHaveExitValue(0);
+                    break;
+                case DIAGNOSTIC:
+                case EXPERIMENTAL:
+                    output.shouldNotHaveExitValue(0);
+                    break;
+            }
+        }
+
+        if (false) { // When ShenandoahGC is experimental flag, this makes no sense to test
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:-UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    h,
+                    "-version"
+            );
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            switch (mode) {
+                case PRODUCT:
+                case DIAGNOSTIC:
+                    output.shouldHaveExitValue(0);
+                    break;
+                case EXPERIMENTAL:
+                    output.shouldNotHaveExitValue(0);
+                    break;
+            }
+        }
+
+        {
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:-UnlockDiagnosticVMOptions",
+                    "-XX:+UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    h,
+                    "-version"
+            );
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            switch (mode) {
+                case PRODUCT:
+                case EXPERIMENTAL:
+                    output.shouldHaveExitValue(0);
+                    break;
+                case DIAGNOSTIC:
+                    output.shouldNotHaveExitValue(0);
+                    break;
+            }
+        }
+    }
+
+}
# HG changeset patch
# User shade
# Date 1586258327 -7200
#      Tue Apr 07 13:18:47 2020 +0200
# Node ID 34a6d550f96f2af30b8987f280eae97b7792e838
# Parent  fbbd9bde2c7858883a2edc3aaa5fee1328ff365d
[backport] 8242273: Shenandoah: accept either SATB or IU barriers, but not both
Reviewed-by: rkennke

diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahAggressiveHeuristics.cpp
@@ -41,12 +41,6 @@
   if (ClassUnloading) {
     SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahUnloadClassesFrequency, 1);
   }
-
-  // Final configuration checks
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
 
 void ShenandoahAggressiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset,
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahCompactHeuristics.cpp
@@ -40,12 +40,6 @@
   SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahUncommitDelay,        1000);
   SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahGuaranteedGCInterval, 30000);
   SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahGarbageThreshold,     10);
-
-  // Final configuration checks
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
 
 bool ShenandoahCompactHeuristics::should_start_gc() const {
diff --git a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
--- a/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/heuristics/shenandoahStaticHeuristics.cpp
@@ -33,12 +33,6 @@
 ShenandoahStaticHeuristics::ShenandoahStaticHeuristics() : ShenandoahHeuristics() {
   SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent);
   SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent);
-
-  // Final configuration checks
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier || ShenandoahStoreValEnqueueBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
-  SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
 }
 
 ShenandoahStaticHeuristics::~ShenandoahStaticHeuristics() {}
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeuristics.hpp
@@ -55,14 +55,6 @@
     }                                                                       \
   } while (0)
 
-#define SHENANDOAH_CHECK_FLAG_SET(name)                                     \
-  do {                                                                      \
-    if (!(name)) {                                                          \
-      err_msg message("Heuristics needs -XX:+" #name " to work correctly"); \
-      vm_exit_during_initialization("Error", message);                      \
-    }                                                                       \
-  } while (0)
-
 class ShenandoahCollectionSet;
 class ShenandoahHeapRegion;
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahIUMode.cpp
@@ -31,14 +31,19 @@
 #include "gc_implementation/shenandoah/shenandoahLogging.hpp"
 
 void ShenandoahIUMode::initialize_flags() const {
-  FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, true);
-  FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false);
+  if (FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier)) {
+    FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, true);
+  }
+  if (FLAG_IS_DEFAULT(ShenandoahSATBBarrier)) {
+    FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false);
+  }
 
   SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent);
   SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent);
 
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
+  SHENANDOAH_CHECK_FLAG_UNSET(ShenandoahSATBBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahMode.hpp
@@ -28,6 +28,22 @@
 
 class ShenandoahHeuristics;
 
+#define SHENANDOAH_CHECK_FLAG_SET(name)                                     \
+  do {                                                                      \
+    if (!(name)) {                                                          \
+      err_msg message("GC mode needs -XX:+" #name " to work correctly");    \
+      vm_exit_during_initialization("Error", message);                      \
+    }                                                                       \
+  } while (0)
+
+#define SHENANDOAH_CHECK_FLAG_UNSET(name)                                   \
+  do {                                                                      \
+    if ((name)) {                                                           \
+      err_msg message("GC mode needs -XX:-" #name " to work correctly");    \
+      vm_exit_during_initialization("Error", message);                      \
+    }                                                                       \
+  } while (0)
+
 class ShenandoahMode : public CHeapObj<mtGC> {
 public:
   virtual void initialize_flags() const = 0;
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahNormalMode.cpp
@@ -34,6 +34,7 @@
 
   // Final configuration checks
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
+  SHENANDOAH_CHECK_FLAG_UNSET(ShenandoahStoreValEnqueueBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);
diff --git a/test/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
--- a/test/gc/shenandoah/options/TestWrongBarrierDisable.java
+++ b/test/gc/shenandoah/options/TestWrongBarrierDisable.java
@@ -43,6 +43,7 @@
         };
         String[] iu = {
                 "ShenandoahLoadRefBarrier",
+                "ShenandoahStoreValEnqueueBarrier",
                 "ShenandoahCASBarrier",
                 "ShenandoahCloneBarrier",
         };
@@ -68,7 +69,7 @@
             );
             OutputAnalyzer output = new OutputAnalyzer(pb.start());
             output.shouldHaveExitValue(1);
-            output.shouldContain("Heuristics needs ");
+            output.shouldContain("GC mode needs ");
             output.shouldContain("to work correctly");
         }
     }
diff --git a/test/gc/shenandoah/options/TestWrongBarrierEnable.java b/test/gc/shenandoah/options/TestWrongBarrierEnable.java
new file mode 100644
--- /dev/null
+++ b/test/gc/shenandoah/options/TestWrongBarrierEnable.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/* @test TestWrongBarrierEnable
+ * @summary Test that disabling wrong barriers fails early
+ * @key gc
+ * @library /testlibrary
+ * @run main/othervm TestWrongBarrierEnable
+ */
+
+import java.util.*;
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestWrongBarrierEnable {
+
+    public static void main(String[] args) throws Exception {
+        String[] concurrent = {
+                "ShenandoahStoreValEnqueueBarrier",
+        };
+        String[] iu = {
+                "ShenandoahSATBBarrier",
+        };
+
+        shouldFailAll("-XX:ShenandoahGCHeuristics=adaptive",   concurrent);
+        shouldFailAll("-XX:ShenandoahGCHeuristics=static",     concurrent);
+        shouldFailAll("-XX:ShenandoahGCHeuristics=compact",    concurrent);
+        shouldFailAll("-XX:ShenandoahGCHeuristics=aggressive", concurrent);
+        shouldFailAll("-XX:ShenandoahGCMode=iu",               iu);
+        shouldPassAll("-XX:ShenandoahGCMode=passive",          concurrent);
+        shouldPassAll("-XX:ShenandoahGCMode=passive",          iu);
+    }
+
+    private static void shouldFailAll(String h, String[] barriers) throws Exception {
+        for (String b : barriers) {
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:+UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    h,
+                    "-XX:+" + b,
+                    "-version"
+            );
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            output.shouldNotHaveExitValue(0);
+            output.shouldContain("GC mode needs ");
+            output.shouldContain("to work correctly");
+        }
+    }
+
+    private static void shouldPassAll(String h, String[] barriers) throws Exception {
+        for (String b : barriers) {
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                    "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:+UnlockExperimentalVMOptions",
+                    "-XX:+UseShenandoahGC",
+                    h,
+                    "-XX:+" + b,
+                    "-version"
+            );
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            output.shouldHaveExitValue(0);
+        }
+    }
+
+}
# HG changeset patch
# User rkennke
# Date 1586291478 -7200
#      Tue Apr 07 22:31:18 2020 +0200
# Node ID dbba6ebc3a08a0a1779b580282163b97d26aaecd
# Parent  34a6d550f96f2af30b8987f280eae97b7792e838
[backport] 8242301: Shenandoah: Inline LRB runtime call
Reviewed-by: zgu

diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.cpp
@@ -180,19 +180,6 @@
 }
 
 
-oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj) {
-  assert(ShenandoahLoadRefBarrier, "should be enabled");
-  assert(_heap->is_evacuation_in_progress(), "evac should be in progress");
-  shenandoah_assert_in_cset(NULL, obj);
-
-  oop fwd = resolve_forwarded_not_null(obj);
-  if (obj == fwd) {
-    ShenandoahEvacOOMScope scope;
-    return _heap->evacuate_object(obj, Thread::current());
-  }
-  return fwd;
-}
-
 oop ShenandoahBarrierSet::load_reference_barrier_impl(oop obj) {
   assert(ShenandoahLoadRefBarrier, "should be enabled");
   if (!oopDesc::is_null(obj)) {
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.hpp
@@ -108,8 +108,8 @@
   void storeval_barrier(oop obj);
 
   oop load_reference_barrier(oop obj);
-  oop load_reference_barrier_mutator(oop obj);
   oop load_reference_barrier_not_null(oop obj);
+  inline oop load_reference_barrier_mutator(oop obj);
 
   oop oop_atomic_cmpxchg_in_heap(oop new_value, volatile HeapWord* dest, oop compare_value);
 
diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahBarrierSet.inline.hpp
@@ -44,6 +44,21 @@
   }
 }
 
+inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj) {
+  assert(ShenandoahLoadRefBarrier, "should be enabled");
+  shenandoah_assert_in_cset(NULL, obj);
+
+  oop fwd = resolve_forwarded_not_null(obj);
+  if (obj == fwd) {
+    assert(_heap->is_evacuation_in_progress(),
+           "evac should be in progress");
+    ShenandoahEvacOOMScope scope;
+    fwd = _heap->evacuate_object(obj, Thread::current());
+  }
+
+  return fwd;
+}
+
 template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
 void ShenandoahBarrierSet::arraycopy_work(T* src, size_t count) {
   assert(HAS_FWD == _heap->has_forwarded_objects(), "Forwarded object status is sane");
# HG changeset patch
# User rkennke
# Date 1586338009 -7200
#      Wed Apr 08 11:26:49 2020 +0200
# Node ID 1ec8b9e0dfa6a7a28e0231698c5c9dbef00ab191
# Parent  dbba6ebc3a08a0a1779b580282163b97d26aaecd
[backport] 8242316: Shenandoah: Turn NULL-check into assert in SATB slow-path entry
Reviewed-by: zgu, shade

diff --git a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
--- a/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
+++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRuntime.cpp
@@ -40,10 +40,7 @@
 
 // Shenandoah pre write barrier slowpath
 JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre_entry(oopDesc* orig, JavaThread *thread))
-  if (orig == NULL) {
-    assert(false, "should be optimized out");
-    return;
-  }
+  assert(orig != NULL, "should be optimized out");
   shenandoah_assert_correct(NULL, orig);
   // store the original value that was in the field reference
   assert(thread->satb_mark_queue().is_active(), "Shouldn't be here otherwise");