Merge metal-prototype-branch
authorjdv
Fri, 28 Jun 2019 14:36:42 +0530
branchmetal-prototype-branch
changeset 57440 10f701a91883
parent 57431 d5ab3442e44f (current diff)
parent 55519 c59f36ed7b52 (diff)
child 57441 ee34e24af607
Merge
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ArrayRangePostWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ArrayRangePreWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1PostWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1PreWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ReferentFieldReadBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/ArrayRangeWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/ObjectWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/SerialArrayRangeWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/SerialWriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Log.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java
--- a/.hgtags	Wed Jun 26 14:28:47 2019 +0530
+++ b/.hgtags	Fri Jun 28 14:36:42 2019 +0530
@@ -567,3 +567,5 @@
 2f4e214781a1d597ed36bf5a36f20928c6c82996 jdk-14+1
 0692b67f54621991ba7afbf23e55b788f3555e69 jdk-13+26
 43627549a488b7d0b4df8fad436e36233df89877 jdk-14+2
+b7f68ddec66f996ae3aad03291d129ca9f02482d jdk-13+27
+e64383344f144217c36196c3c8a2df8f588a2af3 jdk-14+3
--- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -63,27 +63,25 @@
     return;
   }
 
-  // rscratch1 can be passed as src or dst, so don't use it.
-  RegSet savedRegs = RegSet::of(rscratch2, rheapbase);
+  assert_different_registers(rscratch1, rscratch2, src.base());
+  assert_different_registers(rscratch1, rscratch2, dst);
+
+  RegSet savedRegs = RegSet::range(r0,r28) - RegSet::of(dst, rscratch1, rscratch2);
 
   Label done;
-  assert_different_registers(rheapbase, rscratch2, dst);
-  assert_different_registers(rheapbase, rscratch2, src.base());
-
-  __ push(savedRegs, sp);
 
   // Load bad mask into scratch register.
-  __ ldr(rheapbase, address_bad_mask_from_thread(rthread));
+  __ ldr(rscratch1, address_bad_mask_from_thread(rthread));
   __ lea(rscratch2, src);
   __ ldr(dst, src);
 
   // Test reference against bad mask. If mask bad, then we need to fix it up.
-  __ tst(dst, rheapbase);
+  __ tst(dst, rscratch1);
   __ br(Assembler::EQ, done);
 
   __ enter();
 
-  __ push(RegSet::range(r0,r28) - RegSet::of(dst), sp);
+  __ push(savedRegs, sp);
 
   if (c_rarg0 != dst) {
     __ mov(c_rarg0, dst);
@@ -91,13 +89,15 @@
   __ mov(c_rarg1, rscratch2);
 
   int step = 4 * wordSize;
-  __ mov(rscratch1, -step);
+  __ mov(rscratch2, -step);
   __ sub(sp, sp, step);
 
   for (int i = 28; i >= 4; i -= 4) {
     __ st1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2),
-        as_FloatRegister(i+3), __ T1D, Address(__ post(sp, rscratch1)));
+        as_FloatRegister(i+3), __ T1D, Address(__ post(sp, rscratch2)));
   }
+  __ st1(as_FloatRegister(0), as_FloatRegister(1), as_FloatRegister(2),
+      as_FloatRegister(3), __ T1D, Address(sp));
 
   __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2);
 
@@ -111,13 +111,10 @@
     __ mov(dst, r0);
   }
 
-  __ pop(RegSet::range(r0,r28) - RegSet::of(dst), sp);
+  __ pop(savedRegs, sp);
   __ leave();
 
   __ bind(done);
-
-  // Restore tmps
-  __ pop(savedRegs, sp);
 }
 
 #ifdef ASSERT
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -886,8 +886,8 @@
   }
 
   // Get mirror and store it in the frame as GC root for this Method*
-  __ load_mirror(rscratch1, rmethod);
-  __ stp(rscratch1, zr, Address(sp, 4 * wordSize));
+  __ load_mirror(r10, rmethod);
+  __ stp(r10, zr, Address(sp, 4 * wordSize));
 
   __ ldr(rcpool, Address(rmethod, Method::const_offset()));
   __ ldr(rcpool, Address(rcpool, ConstMethod::constants_offset()));
--- a/src/hotspot/share/ci/ciMethodData.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/ci/ciMethodData.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -81,13 +81,13 @@
 // Check for entries that reference an unloaded method
 class PrepareExtraDataClosure : public CleanExtraDataClosure {
   MethodData*            _mdo;
-  uint64_t               _safepoint_counter;
+  SafepointStateTracker  _safepoint_tracker;
   GrowableArray<Method*> _uncached_methods;
 
 public:
   PrepareExtraDataClosure(MethodData* mdo)
     : _mdo(mdo),
-      _safepoint_counter(SafepointSynchronize::safepoint_counter()),
+      _safepoint_tracker(SafepointSynchronize::safepoint_state_tracker()),
       _uncached_methods()
   { }
 
@@ -103,7 +103,7 @@
   }
 
   bool has_safepointed() {
-    return SafepointSynchronize::safepoint_counter() != _safepoint_counter;
+    return _safepoint_tracker.safepoint_state_changed();
   }
 
   bool finish() {
--- a/src/hotspot/share/code/dependencyContext.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/code/dependencyContext.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -99,15 +99,15 @@
   // Safepoints are forbidden during DC lifetime. GC can invalidate
   // _dependency_context_addr if it relocates the holder
   // (e.g. CallSiteContext Java object).
-  uint64_t _safepoint_counter;
+  SafepointStateTracker _safepoint_tracker;
 
   DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr)
     : _dependency_context_addr(bucket_addr),
       _last_cleanup_addr(last_cleanup_addr),
-      _safepoint_counter(SafepointSynchronize::safepoint_counter()) {}
+      _safepoint_tracker(SafepointSynchronize::safepoint_state_tracker()) {}
 
   ~DependencyContext() {
-    assert(SafepointSynchronize::is_same_safepoint(_safepoint_counter), "must be the same safepoint");
+    assert(!_safepoint_tracker.safepoint_state_changed(), "must be the same safepoint");
   }
 #else
   DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr)
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -4250,7 +4250,6 @@
   if (should_unload_classes()) {
     heap->prune_scavengable_nmethods();
   }
-  JvmtiExport::gc_epilogue();
 
   // If we encountered any (marking stack / work queue) overflow
   // events during the current CMS cycle, take appropriate
--- a/src/hotspot/share/gc/g1/g1Analytics.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Analytics.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,7 @@
   0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
 };
 
-static double cost_per_card_ms_defaults[] = {
+static double cost_per_log_buffer_entry_ms_defaults[] = {
   0.01, 0.005, 0.005, 0.003, 0.003, 0.002, 0.002, 0.0015
 };
 
@@ -47,7 +47,7 @@
   1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
 };
 
-static double cost_per_entry_ms_defaults[] = {
+static double young_only_cost_per_remset_card_ms_defaults[] = {
   0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005
 };
 
@@ -77,12 +77,12 @@
     _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
     _prev_collection_pause_end_ms(0.0),
     _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)),
-    _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+    _cost_per_log_buffer_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
     _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)),
     _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
     _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
-    _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
-    _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+    _young_only_cost_per_remset_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+    _mixed_cost_per_remset_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
     _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
     _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
     _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
@@ -101,10 +101,10 @@
   int index = MIN2(ParallelGCThreads - 1, 7u);
 
   _rs_length_diff_seq->add(rs_length_diff_defaults[index]);
-  _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]);
+  _cost_per_log_buffer_entry_ms_seq->add(cost_per_log_buffer_entry_ms_defaults[index]);
   _cost_scan_hcc_seq->add(0.0);
   _young_cards_per_entry_ratio_seq->add(young_cards_per_entry_ratio_defaults[index]);
-  _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]);
+  _young_only_cost_per_remset_card_ms_seq->add(young_only_cost_per_remset_card_ms_defaults[index]);
   _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]);
   _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]);
   _young_other_cost_per_region_ms_seq->add(young_other_cost_per_region_ms_defaults[index]);
@@ -158,19 +158,19 @@
     (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms;
 }
 
-void G1Analytics::report_cost_per_card_ms(double cost_per_card_ms) {
-  _cost_per_card_ms_seq->add(cost_per_card_ms);
+void G1Analytics::report_cost_per_log_buffer_entry_ms(double cost_per_log_buffer_entry_ms) {
+  _cost_per_log_buffer_entry_ms_seq->add(cost_per_log_buffer_entry_ms);
 }
 
 void G1Analytics::report_cost_scan_hcc(double cost_scan_hcc) {
   _cost_scan_hcc_seq->add(cost_scan_hcc);
 }
 
-void G1Analytics::report_cost_per_entry_ms(double cost_per_entry_ms, bool for_young_gc) {
+void G1Analytics::report_cost_per_remset_card_ms(double cost_per_remset_card_ms, bool for_young_gc) {
   if (for_young_gc) {
-    _cost_per_entry_ms_seq->add(cost_per_entry_ms);
+    _young_only_cost_per_remset_card_ms_seq->add(cost_per_remset_card_ms);
   } else {
-    _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms);
+    _mixed_cost_per_remset_card_ms_seq->add(cost_per_remset_card_ms);
   }
 }
 
@@ -222,8 +222,8 @@
   return get_new_prediction(_alloc_rate_ms_seq);
 }
 
-double G1Analytics::predict_cost_per_card_ms() const {
-  return get_new_prediction(_cost_per_card_ms_seq);
+double G1Analytics::predict_cost_per_log_buffer_entry_ms() const {
+  return get_new_prediction(_cost_per_log_buffer_entry_ms_seq);
 }
 
 double G1Analytics::predict_scan_hcc_ms() const {
@@ -231,7 +231,7 @@
 }
 
 double G1Analytics::predict_rs_update_time_ms(size_t pending_cards) const {
-  return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
+  return pending_cards * predict_cost_per_log_buffer_entry_ms() + predict_scan_hcc_ms();
 }
 
 double G1Analytics::predict_young_cards_per_entry_ratio() const {
@@ -256,17 +256,17 @@
 
 double G1Analytics::predict_rs_scan_time_ms(size_t card_num, bool for_young_gc) const {
   if (for_young_gc) {
-    return card_num * get_new_prediction(_cost_per_entry_ms_seq);
+    return card_num * get_new_prediction(_young_only_cost_per_remset_card_ms_seq);
   } else {
     return predict_mixed_rs_scan_time_ms(card_num);
   }
 }
 
 double G1Analytics::predict_mixed_rs_scan_time_ms(size_t card_num) const {
-  if (_mixed_cost_per_entry_ms_seq->num() < 3) {
-    return card_num * get_new_prediction(_cost_per_entry_ms_seq);
+  if (_mixed_cost_per_remset_card_ms_seq->num() < 3) {
+    return card_num * get_new_prediction(_young_only_cost_per_remset_card_ms_seq);
   } else {
-    return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq);
+    return card_num * get_new_prediction(_mixed_cost_per_remset_card_ms_seq);
   }
 }
 
--- a/src/hotspot/share/gc/g1/g1Analytics.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Analytics.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -46,12 +46,12 @@
   double        _prev_collection_pause_end_ms;
 
   TruncatedSeq* _rs_length_diff_seq;
-  TruncatedSeq* _cost_per_card_ms_seq;
+  TruncatedSeq* _cost_per_log_buffer_entry_ms_seq;
   TruncatedSeq* _cost_scan_hcc_seq;
   TruncatedSeq* _young_cards_per_entry_ratio_seq;
   TruncatedSeq* _mixed_cards_per_entry_ratio_seq;
-  TruncatedSeq* _cost_per_entry_ms_seq;
-  TruncatedSeq* _mixed_cost_per_entry_ms_seq;
+  TruncatedSeq* _young_only_cost_per_remset_card_ms_seq;
+  TruncatedSeq* _mixed_cost_per_remset_card_ms_seq;
   TruncatedSeq* _cost_per_byte_ms_seq;
   TruncatedSeq* _constant_other_time_ms_seq;
   TruncatedSeq* _young_other_cost_per_region_ms_seq;
@@ -99,9 +99,9 @@
   void report_concurrent_mark_remark_times_ms(double ms);
   void report_concurrent_mark_cleanup_times_ms(double ms);
   void report_alloc_rate_ms(double alloc_rate);
-  void report_cost_per_card_ms(double cost_per_card_ms);
+  void report_cost_per_log_buffer_entry_ms(double cost_per_log_buffer_entry_ms);
   void report_cost_scan_hcc(double cost_scan_hcc);
-  void report_cost_per_entry_ms(double cost_per_entry_ms, bool for_young_gc);
+  void report_cost_per_remset_card_ms(double cost_per_remset_card_ms, bool for_young_gc);
   void report_cards_per_entry_ratio(double cards_per_entry_ratio, bool for_young_gc);
   void report_rs_length_diff(double rs_length_diff);
   void report_cost_per_byte_ms(double cost_per_byte_ms, bool mark_or_rebuild_in_progress);
@@ -116,7 +116,7 @@
   double predict_alloc_rate_ms() const;
   int num_alloc_rate_ms() const;
 
-  double predict_cost_per_card_ms() const;
+  double predict_cost_per_log_buffer_entry_ms() const;
 
   double predict_scan_hcc_ms() const;
 
--- a/src/hotspot/share/gc/g1/g1CardTable.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CardTable.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -30,28 +30,6 @@
 #include "runtime/atomic.hpp"
 #include "runtime/orderAccess.hpp"
 
-bool G1CardTable::mark_card_deferred(size_t card_index) {
-  CardValue val = _byte_map[card_index];
-  // It's already processed
-  if ((val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val()) {
-    return false;
-  }
-
-  // Cached bit can be installed either on a clean card or on a claimed card.
-  CardValue new_val = val;
-  if (val == clean_card_val()) {
-    new_val = deferred_card_val();
-  } else {
-    if (val & claimed_card_val()) {
-      new_val = val | deferred_card_val();
-    }
-  }
-  if (new_val != val) {
-    Atomic::cmpxchg(new_val, &_byte_map[card_index], val);
-  }
-  return true;
-}
-
 void G1CardTable::g1_mark_as_young(const MemRegion& mr) {
   CardValue *const first = byte_for(mr.start());
   CardValue *const last = byte_after(mr.last());
--- a/src/hotspot/share/gc/g1/g1CardTable.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CardTable.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -44,55 +44,65 @@
   virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled);
 };
 
-class G1CardTable: public CardTable {
+class G1CardTable : public CardTable {
   friend class VMStructs;
   friend class G1CardTableChangedListener;
 
   G1CardTableChangedListener _listener;
 
+public:
   enum G1CardValues {
-    g1_young_gen = CT_MR_BS_last_reserved << 1
+    g1_young_gen = CT_MR_BS_last_reserved << 1,
+
+    // During evacuation we use the card table to consolidate the cards we need to
+    // scan for roots onto the card table from the various sources. Further it is
+    // used to record already completely scanned cards to avoid re-scanning them
+    // when incrementally evacuating the old gen regions of a collection set.
+    // This means that already scanned cards should be preserved.
+    //
+    // The merge at the start of each evacuation round simply sets cards to dirty
+    // that are clean; scanned cards are set to 0x1.
+    //
+    // This means that the LSB determines what to do with the card during evacuation
+    // given the following possible values:
+    //
+    // 11111111 - clean, do not scan
+    // 00000001 - already scanned, do not scan
+    // 00000000 - dirty, needs to be scanned.
+    //
+    g1_card_already_scanned = 0x1
   };
 
-public:
+  static const size_t WordAllClean = SIZE_MAX;
+  static const size_t WordAllDirty = 0;
+
+  STATIC_ASSERT(BitsPerByte == 8);
+  static const size_t WordAlreadyScanned = (SIZE_MAX / 255) * g1_card_already_scanned;
+
   G1CardTable(MemRegion whole_heap): CardTable(whole_heap, /* scanned concurrently */ true), _listener() {
     _listener.set_card_table(this);
   }
-  bool is_card_dirty(size_t card_index) {
-    return _byte_map[card_index] == dirty_card_val();
-  }
 
   static CardValue g1_young_card_val() { return g1_young_gen; }
 
-/*
-   Claimed and deferred bits are used together in G1 during the evacuation
-   pause. These bits can have the following state transitions:
-   1. The claimed bit can be put over any other card state. Except that
-      the "dirty -> dirty and claimed" transition is checked for in
-      G1 code and is not used.
-   2. Deferred bit can be set only if the previous state of the card
-      was either clean or claimed. mark_card_deferred() is wait-free.
-      We do not care if the operation is be successful because if
-      it does not it will only result in duplicate entry in the update
-      buffer because of the "cache-miss". So it's not worth spinning.
- */
-
-  bool is_card_claimed(size_t card_index) {
-    CardValue val = _byte_map[card_index];
-    return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val();
-  }
-
-  inline void set_card_claimed(size_t card_index);
-
   void verify_g1_young_region(MemRegion mr) PRODUCT_RETURN;
   void g1_mark_as_young(const MemRegion& mr);
 
-  bool mark_card_deferred(size_t card_index);
+  size_t index_for_cardvalue(CardValue const* p) const {
+    return pointer_delta(p, _byte_map, sizeof(CardValue));
+  }
+
+  // Mark the given card as Dirty if it is Clean.
+  inline void mark_clean_as_dirty(size_t card_index);
 
-  bool is_card_deferred(size_t card_index) {
-    CardValue val = _byte_map[card_index];
-    return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val();
-  }
+  // Change Clean cards in a (large) area on the card table as Dirty, preserving
+  // already scanned cards. Assumes that most cards in that area are Clean.
+  inline void mark_region_dirty(size_t start_card_index, size_t num_cards);
+
+  // Mark the given range of cards as Scanned. All of these cards must be Dirty.
+  inline void mark_as_scanned(size_t start_card_index, size_t num_cards);
+
+  inline uint region_idx_for(CardValue* p);
 
   static size_t compute_size(size_t mem_region_size_in_words) {
     size_t number_of_slots = (mem_region_size_in_words / card_size_in_words);
--- a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -26,15 +26,58 @@
 #define SHARE_GC_G1_G1CARDTABLE_INLINE_HPP
 
 #include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/heapRegion.hpp"
 
-void G1CardTable::set_card_claimed(size_t card_index) {
-  jbyte val = _byte_map[card_index];
-  if (val == clean_card_val()) {
-    val = (jbyte)claimed_card_val();
-  } else {
-    val |= (jbyte)claimed_card_val();
+inline uint G1CardTable::region_idx_for(CardValue* p) {
+  size_t const card_idx = pointer_delta(p, _byte_map, sizeof(CardValue));
+  return (uint)(card_idx >> (HeapRegion::LogOfHRGrainBytes - card_shift));
+}
+
+inline void G1CardTable::mark_clean_as_dirty(size_t card_index) {
+  CardValue value = _byte_map[card_index];
+  if (value == clean_card_val()) {
+    _byte_map[card_index] = dirty_card_val();
   }
-  _byte_map[card_index] = val;
 }
 
-#endif // SHARE_GC_G1_G1CARDTABLE_INLINE_HPP
+inline void G1CardTable::mark_region_dirty(size_t start_card_index, size_t num_cards) {
+  assert(is_aligned(start_card_index, sizeof(size_t)), "Start card index must be aligned.");
+  assert(is_aligned(num_cards, sizeof(size_t)), "Number of cards to change must be evenly divisible.");
+
+  size_t const num_chunks = num_cards / sizeof(size_t);
+
+  size_t* cur_word = (size_t*)&_byte_map[start_card_index];
+  size_t* const end_word_map = cur_word + num_chunks;
+  while (cur_word < end_word_map) {
+    size_t value = *cur_word;
+    if (value == WordAllClean) {
+      *cur_word = WordAllDirty;
+    } else if (value == WordAllDirty) {
+      // do nothing.
+    } else {
+      // There is a mix of cards in there. Tread slowly.
+      CardValue* cur = (CardValue*)cur_word;
+      for (size_t i = 0; i < sizeof(size_t); i++) {
+        CardValue value = *cur;
+        if (value == clean_card_val()) {
+          *cur = dirty_card_val();
+        }
+        cur++;
+      }
+    }
+    cur_word++;
+  }
+}
+
+inline void G1CardTable::mark_as_scanned(size_t start_card_index, size_t num_cards) {
+  CardValue* start = &_byte_map[start_card_index];
+  CardValue* const end = start + num_cards;
+  while (start < end) {
+    CardValue value = *start;
+    assert(value == dirty_card_val(),
+           "Must have been dirty %d start " PTR_FORMAT " " PTR_FORMAT, value, p2i(start), p2i(end));
+    *start++ = g1_card_already_scanned;
+  }
+}
+
+#endif /* SHARE_GC_G1_G1CARDTABLE_INLINE_HPP */
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -1677,7 +1677,6 @@
   _card_table = ct;
 
   G1BarrierSet::satb_mark_queue_set().initialize(this,
-                                                 SATB_Q_CBL_mon,
                                                  &bs->satb_mark_queue_buffer_allocator(),
                                                  G1SATBProcessCompletedThreshold,
                                                  G1SATBBufferEnqueueingThresholdPercent);
@@ -1955,7 +1954,7 @@
     n_completed_buffers++;
   }
   assert(dcqs.completed_buffers_num() == 0, "Completed buffers exist!");
-  phase_times()->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, n_completed_buffers, G1GCPhaseTimes::UpdateRSProcessedBuffers);
+  phase_times()->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_i, n_completed_buffers, G1GCPhaseTimes::MergeLBProcessedBuffers);
 }
 
 // Computes the sum of the storage used by the various regions.
@@ -2239,8 +2238,8 @@
   _collection_set.iterate(cl);
 }
 
-void G1CollectedHeap::collection_set_iterate_increment_from(HeapRegionClosure *cl, uint worker_id) {
-  _collection_set.iterate_incremental_part_from(cl, worker_id, workers()->active_workers());
+void G1CollectedHeap::collection_set_iterate_increment_from(HeapRegionClosure *cl, HeapRegionClaimer* hr_claimer, uint worker_id) {
+  _collection_set.iterate_incremental_part_from(cl, hr_claimer, worker_id, workers()->active_workers());
 }
 
 HeapWord* G1CollectedHeap::block_start(const void* addr) const {
@@ -2631,8 +2630,6 @@
   size_t _total_humongous;
   size_t _candidate_humongous;
 
-  G1DirtyCardQueue _dcq;
-
   bool humongous_region_is_candidate(G1CollectedHeap* g1h, HeapRegion* region) const {
     assert(region->is_starts_humongous(), "Must start a humongous object");
 
@@ -2692,8 +2689,7 @@
  public:
   RegisterRegionsWithRegionAttrTableClosure()
   : _total_humongous(0),
-    _candidate_humongous(0),
-    _dcq(&G1BarrierSet::dirty_card_queue_set()) {
+    _candidate_humongous(0) {
   }
 
   virtual bool do_heap_region(HeapRegion* r) {
@@ -2708,49 +2704,9 @@
     uint rindex = r->hrm_index();
     g1h->set_humongous_reclaim_candidate(rindex, is_candidate);
     if (is_candidate) {
+      g1h->register_humongous_region_with_region_attr(rindex);
       _candidate_humongous++;
-      g1h->register_humongous_region_with_region_attr(rindex);
-      // Is_candidate already filters out humongous object with large remembered sets.
-      // If we have a humongous object with a few remembered sets, we simply flush these
-      // remembered set entries into the DCQS. That will result in automatic
-      // re-evaluation of their remembered set entries during the following evacuation
-      // phase.
-      if (!r->rem_set()->is_empty()) {
-        guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
-                  "Found a not-small remembered set here. This is inconsistent with previous assumptions.");
-        G1CardTable* ct = g1h->card_table();
-        HeapRegionRemSetIterator hrrs(r->rem_set());
-        size_t card_index;
-        while (hrrs.has_next(card_index)) {
-          CardTable::CardValue* card_ptr = ct->byte_for_index(card_index);
-          // The remembered set might contain references to already freed
-          // regions. Filter out such entries to avoid failing card table
-          // verification.
-          if (g1h->is_in(ct->addr_for(card_ptr))) {
-            if (*card_ptr != G1CardTable::dirty_card_val()) {
-              *card_ptr = G1CardTable::dirty_card_val();
-              _dcq.enqueue(card_ptr);
-            }
-          }
-        }
-        assert(hrrs.n_yielded() == r->rem_set()->occupied(),
-               "Remembered set hash maps out of sync, cur: " SIZE_FORMAT " entries, next: " SIZE_FORMAT " entries",
-               hrrs.n_yielded(), r->rem_set()->occupied());
-        // We should only clear the card based remembered set here as we will not
-        // implicitly rebuild anything else during eager reclaim. Note that at the moment
-        // (and probably never) we do not enter this path if there are other kind of
-        // remembered sets for this region.
-        r->rem_set()->clear_locked(true /* only_cardset */);
-        // Clear_locked() above sets the state to Empty. However we want to continue
-        // collecting remembered set entries for humongous regions that were not
-        // reclaimed.
-        r->rem_set()->set_state_complete();
-#ifdef ASSERT
-        G1HeapRegionAttr region_attr = g1h->region_attr(oop(r->bottom()));
-        assert(region_attr.needs_remset_update(), "must be");
-#endif
-      }
-      assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
+      // We will later handle the remembered sets of these regions.
     } else {
       g1h->register_region_with_region_attr(r);
     }
@@ -2761,8 +2717,6 @@
 
   size_t total_humongous() const { return _total_humongous; }
   size_t candidate_humongous() const { return _candidate_humongous; }
-
-  void flush_rem_set_entries() { _dcq.flush(); }
 };
 
 void G1CollectedHeap::register_regions_with_region_attr() {
@@ -2775,9 +2729,6 @@
                                          cl.total_humongous(),
                                          cl.candidate_humongous());
   _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
-
-  // Finally flush all remembered set entries to re-check into the global DCQS.
-  cl.flush_rem_set_entries();
 }
 
 #ifndef PRODUCT
@@ -3072,7 +3023,7 @@
                                                   workers()->active_workers(),
                                                   collection_set()->young_region_length(),
                                                   collection_set()->optional_region_length());
-        pre_evacuate_collection_set(evacuation_info);
+        pre_evacuate_collection_set(evacuation_info, &per_thread_states);
 
         // Actually do the work...
         evacuate_initial_collection_set(&per_thread_states);
@@ -3105,9 +3056,7 @@
 
         double sample_end_time_sec = os::elapsedTime();
         double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS;
-        size_t total_cards_scanned = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ScanRSScannedCards) +
-                                     phase_times()->sum_thread_work_items(G1GCPhaseTimes::OptScanRS, G1GCPhaseTimes::ScanRSScannedCards);
-        policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc);
+        policy()->record_collection_pause_end(pause_time_ms, heap_used_bytes_before_gc);
       }
 
       verify_after_young_collection(verify_type);
@@ -3581,7 +3530,7 @@
   phase_times()->record_merge_pss_time_ms((os::elapsedTime() - merge_pss_time_start) * 1000.0);
 }
 
-void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info) {
+void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) {
   _expand_heap_after_alloc_failure = true;
   _evacuation_failed = false;
 
@@ -3592,10 +3541,15 @@
   // Initialize the GC alloc regions.
   _allocator->init_gc_alloc_regions(evacuation_info);
 
+  {
+    Ticks start = Ticks::now();
+    rem_set()->prepare_for_scan_heap_roots();
+    phase_times()->record_prepare_heap_roots_time_ms((Ticks::now() - start).seconds() * 1000.0);
+  }
+
   register_regions_with_region_attr();
   assert(_verifier->check_region_attr_table(), "Inconsistency in the region attributes table.");
 
-  rem_set()->prepare_for_scan_rem_set();
   _preserved_marks_set.assert_empty();
 
 #if COMPILER2_OR_JVMCI
@@ -3697,8 +3651,8 @@
 
   void scan_roots(G1ParScanThreadState* pss, uint worker_id) {
     _root_processor->evacuate_roots(pss, worker_id);
-    _g1h->rem_set()->update_rem_set(pss, worker_id);
-    _g1h->rem_set()->scan_rem_set(pss, worker_id, G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ObjCopy, G1GCPhaseTimes::CodeRoots);
+    _g1h->rem_set()->scan_heap_roots(pss, worker_id, G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ObjCopy);
+    _g1h->rem_set()->scan_collection_set_regions(pss, worker_id, G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::CodeRoots, G1GCPhaseTimes::ObjCopy);
   }
 
   void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) {
@@ -3725,6 +3679,14 @@
 };
 
 void G1CollectedHeap::evacuate_initial_collection_set(G1ParScanThreadStateSet* per_thread_states) {
+  G1GCPhaseTimes* p = phase_times();
+
+  {
+    Ticks start = Ticks::now();
+    rem_set()->merge_heap_roots(false /* remset_only */, G1GCPhaseTimes::MergeRS);
+    p->record_merge_heap_roots_time((Ticks::now() - start).seconds() * 1000.0);
+  }
+
   Tickspan task_time;
   const uint num_workers = workers()->active_workers();
 
@@ -3739,7 +3701,6 @@
   }
   Tickspan total_processing = Ticks::now() - start_processing;
 
-  G1GCPhaseTimes* p = phase_times();
   p->record_initial_evac_time(task_time.seconds() * 1000.0);
   p->record_or_add_code_root_fixup_time((total_processing - task_time).seconds() * 1000.0);
 }
@@ -3747,7 +3708,8 @@
 class G1EvacuateOptionalRegionsTask : public G1EvacuateRegionsBaseTask {
 
   void scan_roots(G1ParScanThreadState* pss, uint worker_id) {
-    _g1h->rem_set()->scan_rem_set(pss, worker_id, G1GCPhaseTimes::OptScanRS, G1GCPhaseTimes::OptObjCopy, G1GCPhaseTimes::OptCodeRoots);
+    _g1h->rem_set()->scan_heap_roots(pss, worker_id, G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::OptObjCopy);
+    _g1h->rem_set()->scan_collection_set_regions(pss, worker_id, G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::OptCodeRoots, G1GCPhaseTimes::OptObjCopy);
   }
 
   void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) {
@@ -3783,8 +3745,6 @@
 void G1CollectedHeap::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) {
   const double gc_start_time_ms = phase_times()->cur_collection_start_sec() * 1000.0;
 
-  Ticks start = Ticks::now();
-
   while (!evacuation_failed() && _collection_set.optional_region_length() > 0) {
 
     double time_used_ms = os::elapsedTime() * 1000.0 - gc_start_time_ms;
@@ -3797,18 +3757,24 @@
       break;
     }
 
-    evacuate_next_optional_regions(per_thread_states);
+    {
+      Ticks start = Ticks::now();
+      rem_set()->merge_heap_roots(true /* remset_only */, G1GCPhaseTimes::OptMergeRS);
+      phase_times()->record_or_add_optional_merge_heap_roots_time((Ticks::now() - start).seconds() * 1000.0);
+    }
+
+    {
+      Ticks start = Ticks::now();
+      evacuate_next_optional_regions(per_thread_states);
+      phase_times()->record_or_add_optional_evac_time((Ticks::now() - start).seconds() * 1000.0);
+    }
   }
 
   _collection_set.abandon_optional_collection_set(per_thread_states);
-
-  phase_times()->record_or_add_optional_evac_time((Ticks::now() - start).seconds() * 1000.0);
 }
 
 void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) {
-  // Also cleans the card table from temporary duplicate detection information used
-  // during UpdateRS/ScanRS.
-  rem_set()->cleanup_after_scan_rem_set();
+  rem_set()->cleanup_after_scan_heap_roots();
 
   // Process any discovered reference objects - we have
   // to do this _before_ we retire the GC alloc regions
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -78,7 +78,6 @@
 class G1HotCardCache;
 class G1RemSet;
 class G1YoungRemSetSamplingThread;
-class HeapRegionRemSetIterator;
 class G1ConcurrentMark;
 class G1ConcurrentMarkThread;
 class G1ConcurrentRefine;
@@ -757,7 +756,7 @@
   void evacuate_next_optional_regions(G1ParScanThreadStateSet* per_thread_states);
 
 public:
-  void pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info);
+  void pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss);
   void post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss);
 
   void expand_heap_after_young_collection();
@@ -1115,7 +1114,8 @@
 
  public:
 
-  inline G1HeapRegionAttr region_attr(const void* obj);
+  inline G1HeapRegionAttr region_attr(const void* obj) const;
+  inline G1HeapRegionAttr region_attr(uint idx) const;
 
   // Return "TRUE" iff the given object address is in the reserved
   // region of g1.
@@ -1182,7 +1182,12 @@
   // Starts the iteration so that the start regions of a given worker id over the
   // set active_workers are evenly spread across the set of collection set regions
   // to be iterated.
-  void collection_set_iterate_increment_from(HeapRegionClosure *blk, uint worker_id);
+  // The variant with the HeapRegionClaimer guarantees that the closure will be
+  // applied to a particular region exactly once.
+  void collection_set_iterate_increment_from(HeapRegionClosure *blk, uint worker_id) {
+    collection_set_iterate_increment_from(blk, NULL, worker_id);
+  }
+  void collection_set_iterate_increment_from(HeapRegionClosure *blk, HeapRegionClaimer* hr_claimer, uint worker_id);
 
   // Returns the HeapRegion that contains addr. addr must not be NULL.
   template <class T>
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -163,10 +163,14 @@
   return _region_attr.is_in_cset_or_humongous((HeapWord*)obj);
 }
 
-G1HeapRegionAttr G1CollectedHeap::region_attr(const void* addr) {
+G1HeapRegionAttr G1CollectedHeap::region_attr(const void* addr) const {
   return _region_attr.at((HeapWord*)addr);
 }
 
+G1HeapRegionAttr G1CollectedHeap::region_attr(uint idx) const {
+  return _region_attr.get_by_index(idx);
+}
+
 void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) {
   _region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked());
 }
@@ -177,7 +181,7 @@
 
 void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) {
   _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked());
-  _rem_set->prepare_for_scan_rem_set(r->hrm_index());
+  _rem_set->prepare_for_scan_heap_roots(r->hrm_index());
 }
 
 void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) {
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -217,10 +217,13 @@
   }
 }
 
-void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const {
+void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl,
+                                                    HeapRegionClaimer* hr_claimer,
+                                                    uint worker_id,
+                                                    uint total_workers) const {
   assert_at_safepoint();
 
-  size_t len = _collection_set_cur_length - _inc_part_start;
+  size_t len = increment_length();
   if (len == 0) {
     return;
   }
@@ -229,9 +232,12 @@
   size_t cur_pos = start_pos;
 
   do {
-    HeapRegion* r = _g1h->region_at(_collection_set_regions[cur_pos + _inc_part_start]);
-    bool result = cl->do_heap_region(r);
-    guarantee(!result, "Must not cancel iteration");
+    uint region_idx = _collection_set_regions[cur_pos + _inc_part_start];
+    if (hr_claimer == NULL || hr_claimer->claim_region(region_idx)) {
+      HeapRegion* r = _g1h->region_at(region_idx);
+      bool result = cl->do_heap_region(r);
+      guarantee(!result, "Must not cancel iteration");
+    }
 
     cur_pos++;
     if (cur_pos == len) {
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -36,6 +36,7 @@
 class G1Policy;
 class G1SurvivorRegions;
 class HeapRegion;
+class HeapRegionClaimer;
 class HeapRegionClosure;
 
 // The collection set.
@@ -279,7 +280,12 @@
 
   // Iterate over the current collection set increment applying the given HeapRegionClosure
   // from a starting position determined by the given worker id.
-  void iterate_incremental_part_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const;
+  void iterate_incremental_part_from(HeapRegionClosure* cl, HeapRegionClaimer* hr_claimer, uint worker_id, uint total_workers) const;
+
+  // Returns the length of the current increment in number of regions.
+  size_t increment_length() const { return _collection_set_cur_length - _inc_part_start; }
+  // Returns the length of the whole current collection set in number of regions
+  size_t cur_length() const { return _collection_set_cur_length; }
 
   // Iterate over the entire collection set (all increments calculated so far), applying
   // the given HeapRegionClosure on all of them.
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -2419,12 +2419,13 @@
     abort_marking_if_regular_check_fail();
   }
 
+  // Can't assert qset is empty here, even if not aborted.  If concurrent,
+  // some other thread might be adding to the queue.  If not concurrent,
+  // some other thread might have won the race for the last buffer, but
+  // has not yet decremented the count.
+
   _draining_satb_buffers = false;
 
-  assert(has_aborted() ||
-         _cm->concurrent() ||
-         satb_mq_set.completed_buffers_num() == 0, "invariant");
-
   // again, this was a potentially expensive operation, decrease the
   // limits to get the regular clock call early
   decrease_limits();
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -206,7 +206,7 @@
     // available buffers near green_zone value.  When yellow_size is
     // large we don't want to allow a full step to accumulate before
     // doing any processing, as that might lead to significantly more
-    // than green_zone buffers to be processed by update_rs.
+    // than green_zone buffers to be processed during scanning.
     step = MIN2(step, ParallelGCThreads / 2.0);
   }
   size_t activate_offset = static_cast<size_t>(ceil(step * (worker_i + 1)));
@@ -322,18 +322,18 @@
 }
 
 static size_t calc_new_green_zone(size_t green,
-                                  double update_rs_time,
-                                  size_t update_rs_processed_buffers,
+                                  double log_buffer_scan_time,
+                                  size_t processed_log_buffers,
                                   double goal_ms) {
   // Adjust green zone based on whether we're meeting the time goal.
   // Limit to max_green_zone.
   const double inc_k = 1.1, dec_k = 0.9;
-  if (update_rs_time > goal_ms) {
+  if (log_buffer_scan_time > goal_ms) {
     if (green > 0) {
       green = static_cast<size_t>(green * dec_k);
     }
-  } else if (update_rs_time < goal_ms &&
-             update_rs_processed_buffers > green) {
+  } else if (log_buffer_scan_time < goal_ms &&
+             processed_log_buffers > green) {
     green = static_cast<size_t>(MAX2(green * inc_k, green + 1.0));
     green = MIN2(green, max_green_zone);
   }
@@ -350,20 +350,20 @@
   return MIN2(yellow + (yellow - green), max_red_zone);
 }
 
-void G1ConcurrentRefine::update_zones(double update_rs_time,
-                                      size_t update_rs_processed_buffers,
+void G1ConcurrentRefine::update_zones(double log_buffer_scan_time,
+                                      size_t processed_log_buffers,
                                       double goal_ms) {
   log_trace( CTRL_TAGS )("Updating Refinement Zones: "
-                         "update_rs time: %.3fms, "
-                         "update_rs buffers: " SIZE_FORMAT ", "
-                         "update_rs goal time: %.3fms",
-                         update_rs_time,
-                         update_rs_processed_buffers,
+                         "log buffer scan time: %.3fms, "
+                         "processed buffers: " SIZE_FORMAT ", "
+                         "goal time: %.3fms",
+                         log_buffer_scan_time,
+                         processed_log_buffers,
                          goal_ms);
 
   _green_zone = calc_new_green_zone(_green_zone,
-                                    update_rs_time,
-                                    update_rs_processed_buffers,
+                                    log_buffer_scan_time,
+                                    processed_log_buffers,
                                     goal_ms);
   _yellow_zone = calc_new_yellow_zone(_green_zone, _min_yellow_zone_size);
   _red_zone = calc_new_red_zone(_green_zone, _yellow_zone);
@@ -376,13 +376,13 @@
             _green_zone, _yellow_zone, _red_zone);
 }
 
-void G1ConcurrentRefine::adjust(double update_rs_time,
-                                size_t update_rs_processed_buffers,
+void G1ConcurrentRefine::adjust(double log_buffer_scan_time,
+                                size_t processed_log_buffers,
                                 double goal_ms) {
   G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
 
   if (G1UseAdaptiveConcRefinement) {
-    update_zones(update_rs_time, update_rs_processed_buffers, goal_ms);
+    update_zones(log_buffer_scan_time, processed_log_buffers, goal_ms);
 
     // Change the barrier params
     if (max_num_threads() == 0) {
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -97,8 +97,8 @@
                      size_t min_yellow_zone_size);
 
   // Update green/yellow/red zone values based on how well goals are being met.
-  void update_zones(double update_rs_time,
-                    size_t update_rs_processed_buffers,
+  void update_zones(double log_buffer_scan_time,
+                    size_t processed_log_buffers,
                     double goal_ms);
 
   static uint worker_id_offset();
@@ -115,7 +115,7 @@
   void stop();
 
   // Adjust refinement thresholds based on work done during the pause and the goal time.
-  void adjust(double update_rs_time, size_t update_rs_processed_buffers, double goal_ms);
+  void adjust(double log_buffer_scan_time, size_t processed_log_buffers, double goal_ms);
 
   size_t activation_threshold(uint worker_id) const;
   size_t deactivation_threshold(uint worker_id) const;
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -78,7 +78,14 @@
 }
 
 G1DirtyCardQueueSet::G1DirtyCardQueueSet(bool notify_when_complete) :
-  PtrQueueSet(notify_when_complete),
+  PtrQueueSet(),
+  _cbl_mon(NULL),
+  _completed_buffers_head(NULL),
+  _completed_buffers_tail(NULL),
+  _n_completed_buffers(0),
+  _process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever),
+  _process_completed_buffers(false),
+  _notify_when_complete(notify_when_complete),
   _max_completed_buffers(MaxCompletedBuffersUnlimited),
   _completed_buffers_padding(0),
   _free_ids(NULL),
@@ -90,6 +97,7 @@
 }
 
 G1DirtyCardQueueSet::~G1DirtyCardQueueSet() {
+  abandon_completed_buffers();
   delete _free_ids;
 }
 
@@ -101,7 +109,9 @@
 void G1DirtyCardQueueSet::initialize(Monitor* cbl_mon,
                                      BufferNode::Allocator* allocator,
                                      bool init_free_ids) {
-  PtrQueueSet::initialize(cbl_mon, allocator);
+  PtrQueueSet::initialize(allocator);
+  assert(_cbl_mon == NULL, "Init order issue?");
+  _cbl_mon = cbl_mon;
   if (init_free_ids) {
     _free_ids = new G1FreeIdSet(0, num_par_ids());
   }
@@ -111,6 +121,123 @@
   G1ThreadLocalData::dirty_card_queue(t).handle_zero_index();
 }
 
+void G1DirtyCardQueueSet::enqueue_completed_buffer(BufferNode* cbn) {
+  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+  cbn->set_next(NULL);
+  if (_completed_buffers_tail == NULL) {
+    assert(_completed_buffers_head == NULL, "Well-formedness");
+    _completed_buffers_head = cbn;
+    _completed_buffers_tail = cbn;
+  } else {
+    _completed_buffers_tail->set_next(cbn);
+    _completed_buffers_tail = cbn;
+  }
+  _n_completed_buffers++;
+
+  if (!process_completed_buffers() &&
+      (_n_completed_buffers > process_completed_buffers_threshold())) {
+    set_process_completed_buffers(true);
+    if (_notify_when_complete) {
+      _cbl_mon->notify_all();
+    }
+  }
+  assert_completed_buffers_list_len_correct_locked();
+}
+
+BufferNode* G1DirtyCardQueueSet::get_completed_buffer(size_t stop_at) {
+  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+
+  if (_n_completed_buffers <= stop_at) {
+    return NULL;
+  }
+
+  assert(_n_completed_buffers > 0, "invariant");
+  assert(_completed_buffers_head != NULL, "invariant");
+  assert(_completed_buffers_tail != NULL, "invariant");
+
+  BufferNode* bn = _completed_buffers_head;
+  _n_completed_buffers--;
+  _completed_buffers_head = bn->next();
+  if (_completed_buffers_head == NULL) {
+    assert(_n_completed_buffers == 0, "invariant");
+    _completed_buffers_tail = NULL;
+    set_process_completed_buffers(false);
+  }
+  assert_completed_buffers_list_len_correct_locked();
+  bn->set_next(NULL);
+  return bn;
+}
+
+void G1DirtyCardQueueSet::abandon_completed_buffers() {
+  BufferNode* buffers_to_delete = NULL;
+  {
+    MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+    buffers_to_delete = _completed_buffers_head;
+    _completed_buffers_head = NULL;
+    _completed_buffers_tail = NULL;
+    _n_completed_buffers = 0;
+    set_process_completed_buffers(false);
+  }
+  while (buffers_to_delete != NULL) {
+    BufferNode* bn = buffers_to_delete;
+    buffers_to_delete = bn->next();
+    bn->set_next(NULL);
+    deallocate_buffer(bn);
+  }
+}
+
+void G1DirtyCardQueueSet::notify_if_necessary() {
+  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+  if (_n_completed_buffers > process_completed_buffers_threshold()) {
+    set_process_completed_buffers(true);
+    if (_notify_when_complete)
+      _cbl_mon->notify();
+  }
+}
+
+#ifdef ASSERT
+void G1DirtyCardQueueSet::assert_completed_buffers_list_len_correct_locked() {
+  assert_lock_strong(_cbl_mon);
+  size_t n = 0;
+  for (BufferNode* bn = _completed_buffers_head; bn != NULL; bn = bn->next()) {
+    ++n;
+  }
+  assert(n == _n_completed_buffers,
+         "Completed buffer length is wrong: counted: " SIZE_FORMAT
+         ", expected: " SIZE_FORMAT, n, _n_completed_buffers);
+}
+#endif // ASSERT
+
+// Merge lists of buffers. Notify the processing threads.
+// The source queue is emptied as a result. The queues
+// must share the monitor.
+void G1DirtyCardQueueSet::merge_bufferlists(G1DirtyCardQueueSet *src) {
+  assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
+  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
+  if (_completed_buffers_tail == NULL) {
+    assert(_completed_buffers_head == NULL, "Well-formedness");
+    _completed_buffers_head = src->_completed_buffers_head;
+    _completed_buffers_tail = src->_completed_buffers_tail;
+  } else {
+    assert(_completed_buffers_head != NULL, "Well formedness");
+    if (src->_completed_buffers_head != NULL) {
+      _completed_buffers_tail->set_next(src->_completed_buffers_head);
+      _completed_buffers_tail = src->_completed_buffers_tail;
+    }
+  }
+  _n_completed_buffers += src->_n_completed_buffers;
+
+  src->_n_completed_buffers = 0;
+  src->_completed_buffers_head = NULL;
+  src->_completed_buffers_tail = NULL;
+  src->set_process_completed_buffers(false);
+
+  assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
+         _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
+         "Sanity");
+  assert_completed_buffers_list_len_correct_locked();
+}
+
 bool G1DirtyCardQueueSet::apply_closure_to_buffer(G1CardTableEntryClosure* cl,
                                                   BufferNode* node,
                                                   bool consume,
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -76,6 +76,21 @@
 };
 
 class G1DirtyCardQueueSet: public PtrQueueSet {
+  Monitor* _cbl_mon;  // Protects the fields below.
+  BufferNode* _completed_buffers_head;
+  BufferNode* _completed_buffers_tail;
+  volatile size_t _n_completed_buffers;
+
+  size_t _process_completed_buffers_threshold;
+  volatile bool _process_completed_buffers;
+
+  // If true, notify_all on _cbl_mon when the threshold is reached.
+  bool _notify_when_complete;
+
+  void assert_completed_buffers_list_len_correct_locked() NOT_DEBUG_RETURN;
+
+  void abandon_completed_buffers();
+
   // Apply the closure to the elements of "node" from it's index to
   // buffer_size.  If all closure applications return true, then
   // returns true.  Stops processing after the first closure
@@ -111,7 +126,7 @@
   // mutator must start doing some of the concurrent refinement work,
   size_t _max_completed_buffers;
   size_t _completed_buffers_padding;
-  static const size_t MaxCompletedBuffersUnlimited = ~size_t(0);
+  static const size_t MaxCompletedBuffersUnlimited = SIZE_MAX;
 
   G1FreeIdSet* _free_ids;
 
@@ -142,6 +157,34 @@
   // it can be reused in place.
   bool process_or_enqueue_completed_buffer(BufferNode* node);
 
+  virtual void enqueue_completed_buffer(BufferNode* node);
+
+  // If the number of completed buffers is > stop_at, then remove and
+  // return a completed buffer from the list.  Otherwise, return NULL.
+  BufferNode* get_completed_buffer(size_t stop_at = 0);
+
+  // The number of buffers in the list.  Racy...
+  size_t completed_buffers_num() const { return _n_completed_buffers; }
+
+  bool process_completed_buffers() { return _process_completed_buffers; }
+  void set_process_completed_buffers(bool x) { _process_completed_buffers = x; }
+
+  // Get/Set the number of completed buffers that triggers log processing.
+  // Log processing should be done when the number of buffers exceeds the
+  // threshold.
+  void set_process_completed_buffers_threshold(size_t sz) {
+    _process_completed_buffers_threshold = sz;
+  }
+  size_t process_completed_buffers_threshold() const {
+    return _process_completed_buffers_threshold;
+  }
+  static const size_t ProcessCompletedBuffersThresholdNever = SIZE_MAX;
+
+  // Notify the consumer if the number of buffers crossed the threshold
+  void notify_if_necessary();
+
+  void merge_bufferlists(G1DirtyCardQueueSet* src);
+
   // Apply G1RefineCardConcurrentlyClosure to completed buffers until there are stop_at
   // completed buffers remaining.
   bool refine_completed_buffer_concurrently(uint worker_i, size_t stop_at);
@@ -150,13 +193,13 @@
   // must never return false. Must only be called during GC.
   bool apply_closure_during_gc(G1CardTableEntryClosure* cl, uint worker_i);
 
-  void reset_for_par_iteration() { _cur_par_buffer_node = completed_buffers_head(); }
+  void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; }
   // Applies the current closure to all completed buffers, non-consumptively.
   // Can be used in parallel, all callers using the iteration state initialized
   // by reset_for_par_iteration.
   void par_apply_closure_to_all_completed_buffers(G1CardTableEntryClosure* cl);
 
-  // If a full collection is happening, reset partial logs, and ignore
+  // If a full collection is happening, reset partial logs, and release
   // completed ones: the full collection will make them all irrelevant.
   void abandon_logs();
 
--- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -37,15 +37,19 @@
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oop.inline.hpp"
 
-class UpdateRSetDeferred : public BasicOopIterateClosure {
+class UpdateLogBuffersDeferred : public BasicOopIterateClosure {
 private:
   G1CollectedHeap* _g1h;
   G1DirtyCardQueue* _dcq;
   G1CardTable*    _ct;
 
+  // Remember the last enqueued card to avoid enqueuing the same card over and over;
+  // since we only ever handle a card once, this is sufficient.
+  size_t _last_enqueued_card;
+
 public:
-  UpdateRSetDeferred(G1DirtyCardQueue* dcq) :
-    _g1h(G1CollectedHeap::heap()), _dcq(dcq), _ct(_g1h->card_table()) {}
+  UpdateLogBuffersDeferred(G1DirtyCardQueue* dcq) :
+    _g1h(G1CollectedHeap::heap()), _dcq(dcq), _ct(_g1h->card_table()), _last_enqueued_card(SIZE_MAX) {}
 
   virtual void do_oop(narrowOop* p) { do_oop_work(p); }
   virtual void do_oop(      oop* p) { do_oop_work(p); }
@@ -62,8 +66,9 @@
       return;
     }
     size_t card_index = _ct->index_for(p);
-    if (_ct->mark_card_deferred(card_index)) {
+    if (card_index != _last_enqueued_card) {
       _dcq->enqueue(_ct->byte_for_index(card_index));
+      _last_enqueued_card = card_index;
     }
   }
 };
@@ -73,21 +78,21 @@
   G1ConcurrentMark* _cm;
   HeapRegion* _hr;
   size_t _marked_bytes;
-  UpdateRSetDeferred* _update_rset_cl;
+  UpdateLogBuffersDeferred* _log_buffer_cl;
   bool _during_initial_mark;
   uint _worker_id;
   HeapWord* _last_forwarded_object_end;
 
 public:
   RemoveSelfForwardPtrObjClosure(HeapRegion* hr,
-                                 UpdateRSetDeferred* update_rset_cl,
+                                 UpdateLogBuffersDeferred* log_buffer_cl,
                                  bool during_initial_mark,
                                  uint worker_id) :
     _g1h(G1CollectedHeap::heap()),
     _cm(_g1h->concurrent_mark()),
     _hr(hr),
     _marked_bytes(0),
-    _update_rset_cl(update_rset_cl),
+    _log_buffer_cl(log_buffer_cl),
     _during_initial_mark(during_initial_mark),
     _worker_id(worker_id),
     _last_forwarded_object_end(hr->bottom()) { }
@@ -144,7 +149,7 @@
       // The problem is that, if evacuation fails, we might have
       // remembered set entries missing given that we skipped cards on
       // the collection set. So, we'll recreate such entries now.
-      obj->oop_iterate(_update_rset_cl);
+      obj->oop_iterate(_log_buffer_cl);
 
       HeapWord* obj_end = obj_addr + obj_size;
       _last_forwarded_object_end = obj_end;
@@ -193,25 +198,22 @@
 class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure {
   G1CollectedHeap* _g1h;
   uint _worker_id;
-  HeapRegionClaimer* _hrclaimer;
 
   G1DirtyCardQueue _dcq;
-  UpdateRSetDeferred _update_rset_cl;
+  UpdateLogBuffersDeferred _log_buffer_cl;
 
 public:
-  RemoveSelfForwardPtrHRClosure(uint worker_id,
-                                HeapRegionClaimer* hrclaimer) :
+  RemoveSelfForwardPtrHRClosure(uint worker_id) :
     _g1h(G1CollectedHeap::heap()),
     _worker_id(worker_id),
-    _hrclaimer(hrclaimer),
     _dcq(&_g1h->dirty_card_queue_set()),
-    _update_rset_cl(&_dcq){
+    _log_buffer_cl(&_dcq) {
   }
 
   size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr,
                                                bool during_initial_mark) {
     RemoveSelfForwardPtrObjClosure rspc(hr,
-                                        &_update_rset_cl,
+                                        &_log_buffer_cl,
                                         during_initial_mark,
                                         _worker_id);
     hr->object_iterate(&rspc);
@@ -225,26 +227,24 @@
     assert(!hr->is_pinned(), "Unexpected pinned region at index %u", hr->hrm_index());
     assert(hr->in_collection_set(), "bad CS");
 
-    if (_hrclaimer->claim_region(hr->hrm_index())) {
-      if (hr->evacuation_failed()) {
-        hr->clear_index_in_opt_cset();
+    if (hr->evacuation_failed()) {
+      hr->clear_index_in_opt_cset();
 
-        bool during_initial_mark = _g1h->collector_state()->in_initial_mark_gc();
-        bool during_conc_mark = _g1h->collector_state()->mark_or_rebuild_in_progress();
+      bool during_initial_mark = _g1h->collector_state()->in_initial_mark_gc();
+      bool during_conc_mark = _g1h->collector_state()->mark_or_rebuild_in_progress();
 
-        hr->note_self_forwarding_removal_start(during_initial_mark,
+      hr->note_self_forwarding_removal_start(during_initial_mark,
                                                during_conc_mark);
-        _g1h->verifier()->check_bitmaps("Self-Forwarding Ptr Removal", hr);
+      _g1h->verifier()->check_bitmaps("Self-Forwarding Ptr Removal", hr);
 
-        hr->reset_bot();
-
-        size_t live_bytes = remove_self_forward_ptr_by_walking_hr(hr, during_initial_mark);
+      hr->reset_bot();
 
-        hr->rem_set()->clean_strong_code_roots(hr);
-        hr->rem_set()->clear_locked(true);
+      size_t live_bytes = remove_self_forward_ptr_by_walking_hr(hr, during_initial_mark);
 
-        hr->note_self_forwarding_removal_end(live_bytes);
-      }
+      hr->rem_set()->clean_strong_code_roots(hr);
+      hr->rem_set()->clear_locked(true);
+
+      hr->note_self_forwarding_removal_end(live_bytes);
     }
     return false;
   }
@@ -256,7 +256,7 @@
   _hrclaimer(_g1h->workers()->active_workers()) { }
 
 void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) {
-  RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer);
+  RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id);
 
-  _g1h->collection_set_iterate_increment_from(&rsfp_cl, worker_id);
+  _g1h->collection_set_iterate_increment_from(&rsfp_cl, &_hrclaimer, worker_id);
 }
--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -183,7 +183,6 @@
   update_derived_pointers();
 
   BiasedLocking::restore_marks();
-  JvmtiExport::gc_epilogue();
 
   _heap->prepare_heap_for_mutators();
 
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -66,14 +66,30 @@
   _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray<double>(max_gc_threads, "Wait For Strong CLD (ms):");
   _gc_par_phases[WeakCLDRoots] = new WorkerDataArray<double>(max_gc_threads, "Weak CLD Roots (ms):");
 
-  _gc_par_phases[UpdateRS] = new WorkerDataArray<double>(max_gc_threads, "Update RS (ms):");
+  _gc_par_phases[MergeRS] = new WorkerDataArray<double>(max_gc_threads, "Remembered Sets (ms):");
+  _merge_rs_merged_sparse = new WorkerDataArray<size_t>(max_gc_threads, "Merged Sparse:");
+  _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_sparse, MergeRSMergedSparse);
+  _merge_rs_merged_fine = new WorkerDataArray<size_t>(max_gc_threads, "Merged Fine:");
+  _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_fine, MergeRSMergedFine);
+  _merge_rs_merged_coarse = new WorkerDataArray<size_t>(max_gc_threads, "Merged Coarse:");
+  _gc_par_phases[MergeRS]->link_thread_work_items(_merge_rs_merged_coarse, MergeRSMergedCoarse);
+
+  _gc_par_phases[OptMergeRS] = new WorkerDataArray<double>(max_gc_threads, "Optional Remembered Sets (ms):");
+  _opt_merge_rs_merged_sparse = new WorkerDataArray<size_t>(max_gc_threads, "Merged Sparse:");
+  _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_merged_sparse, MergeRSMergedSparse);
+  _opt_merge_rs_merged_fine = new WorkerDataArray<size_t>(max_gc_threads, "Merged Fine:");
+  _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_merged_fine, MergeRSMergedFine);
+  _opt_merge_rs_merged_coarse = new WorkerDataArray<size_t>(max_gc_threads, "Merged Coarse:");
+  _gc_par_phases[OptMergeRS]->link_thread_work_items(_opt_merge_rs_merged_coarse, MergeRSMergedCoarse);
+
+  _gc_par_phases[MergeLB] = new WorkerDataArray<double>(max_gc_threads, "Log Buffers (ms):");
   if (G1HotCardCache::default_use_cache()) {
-    _gc_par_phases[ScanHCC] = new WorkerDataArray<double>(max_gc_threads, "Scan HCC (ms):");
+    _gc_par_phases[MergeHCC] = new WorkerDataArray<double>(max_gc_threads, "Hot Card Cache (ms):");
   } else {
-    _gc_par_phases[ScanHCC] = NULL;
+    _gc_par_phases[MergeHCC] = NULL;
   }
-  _gc_par_phases[ScanRS] = new WorkerDataArray<double>(max_gc_threads, "Scan RS (ms):");
-  _gc_par_phases[OptScanRS] = new WorkerDataArray<double>(max_gc_threads, "Optional Scan RS (ms):");
+  _gc_par_phases[ScanHR] = new WorkerDataArray<double>(max_gc_threads, "Scan Heap Roots (ms):");
+  _gc_par_phases[OptScanHR] = new WorkerDataArray<double>(max_gc_threads, "Optional Scan Heap Roots (ms):");
   _gc_par_phases[CodeRoots] = new WorkerDataArray<double>(max_gc_threads, "Code Root Scan (ms):");
   _gc_par_phases[OptCodeRoots] = new WorkerDataArray<double>(max_gc_threads, "Optional Code Root Scan (ms):");
   _gc_par_phases[ObjCopy] = new WorkerDataArray<double>(max_gc_threads, "Object Copy (ms):");
@@ -84,30 +100,30 @@
   _gc_par_phases[GCWorkerEnd] = new WorkerDataArray<double>(max_gc_threads, "GC Worker End (ms):");
   _gc_par_phases[Other] = new WorkerDataArray<double>(max_gc_threads, "GC Worker Other (ms):");
 
-  _scan_rs_scanned_cards = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Cards:");
-  _gc_par_phases[ScanRS]->link_thread_work_items(_scan_rs_scanned_cards, ScanRSScannedCards);
-  _scan_rs_claimed_cards = new WorkerDataArray<size_t>(max_gc_threads, "Claimed Cards:");
-  _gc_par_phases[ScanRS]->link_thread_work_items(_scan_rs_claimed_cards, ScanRSClaimedCards);
-  _scan_rs_skipped_cards = new WorkerDataArray<size_t>(max_gc_threads, "Skipped Cards:");
-  _gc_par_phases[ScanRS]->link_thread_work_items(_scan_rs_skipped_cards, ScanRSSkippedCards);
+  _scan_hr_scanned_cards = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Cards:");
+  _gc_par_phases[ScanHR]->link_thread_work_items(_scan_hr_scanned_cards, ScanHRScannedCards);
+  _scan_hr_scanned_blocks = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Blocks:");
+  _gc_par_phases[ScanHR]->link_thread_work_items(_scan_hr_scanned_blocks, ScanHRScannedBlocks);
+  _scan_hr_claimed_chunks = new WorkerDataArray<size_t>(max_gc_threads, "Claimed Chunks:");
+  _gc_par_phases[ScanHR]->link_thread_work_items(_scan_hr_claimed_chunks, ScanHRClaimedChunks);
 
-  _opt_scan_rs_scanned_cards = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Cards:");
-  _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_scanned_cards, ScanRSScannedCards);
-  _opt_scan_rs_claimed_cards = new WorkerDataArray<size_t>(max_gc_threads, "Claimed Cards:");
-  _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_claimed_cards, ScanRSClaimedCards);
-  _opt_scan_rs_skipped_cards = new WorkerDataArray<size_t>(max_gc_threads, "Skipped Cards:");
-  _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_skipped_cards, ScanRSSkippedCards);
-  _opt_scan_rs_scanned_opt_refs = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Refs:");
-  _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_scanned_opt_refs, ScanRSScannedOptRefs);
-  _opt_scan_rs_used_memory = new WorkerDataArray<size_t>(max_gc_threads, "Used Memory:");
-  _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_used_memory, ScanRSUsedMemory);
+  _opt_scan_hr_scanned_cards = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Cards:");
+  _gc_par_phases[OptScanHR]->link_thread_work_items(_opt_scan_hr_scanned_cards, ScanHRScannedCards);
+  _opt_scan_hr_scanned_blocks = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Blocks:");
+  _gc_par_phases[OptScanHR]->link_thread_work_items(_opt_scan_hr_scanned_blocks, ScanHRScannedBlocks);
+  _opt_scan_hr_claimed_chunks = new WorkerDataArray<size_t>(max_gc_threads, "Claimed Chunks:");
+  _gc_par_phases[OptScanHR]->link_thread_work_items(_opt_scan_hr_claimed_chunks, ScanHRClaimedChunks);
+  _opt_scan_hr_scanned_opt_refs = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Refs:");
+  _gc_par_phases[OptScanHR]->link_thread_work_items(_opt_scan_hr_scanned_opt_refs, ScanHRScannedOptRefs);
+  _opt_scan_hr_used_memory = new WorkerDataArray<size_t>(max_gc_threads, "Used Memory:");
+  _gc_par_phases[OptScanHR]->link_thread_work_items(_opt_scan_hr_used_memory, ScanHRUsedMemory);
 
-  _update_rs_processed_buffers = new WorkerDataArray<size_t>(max_gc_threads, "Processed Buffers:");
-  _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers, UpdateRSProcessedBuffers);
-  _update_rs_scanned_cards = new WorkerDataArray<size_t>(max_gc_threads, "Scanned Cards:");
-  _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_scanned_cards, UpdateRSScannedCards);
-  _update_rs_skipped_cards = new WorkerDataArray<size_t>(max_gc_threads, "Skipped Cards:");
-  _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_skipped_cards, UpdateRSSkippedCards);
+  _merge_lb_processed_buffers = new WorkerDataArray<size_t>(max_gc_threads, "Processed Buffers:");
+  _gc_par_phases[MergeLB]->link_thread_work_items(_merge_lb_processed_buffers, MergeLBProcessedBuffers);
+  _merge_lb_dirty_cards = new WorkerDataArray<size_t>(max_gc_threads, "Dirty Cards:");
+  _gc_par_phases[MergeLB]->link_thread_work_items(_merge_lb_dirty_cards, MergeLBDirtyCards);
+  _merge_lb_skipped_cards = new WorkerDataArray<size_t>(max_gc_threads, "Skipped Cards:");
+  _gc_par_phases[MergeLB]->link_thread_work_items(_merge_lb_skipped_cards, MergeLBSkippedCards);
 
   _obj_copy_lab_waste = new WorkerDataArray<size_t>(max_gc_threads, "LAB Waste");
   _gc_par_phases[ObjCopy]->link_thread_work_items(_obj_copy_lab_waste, ObjCopyLABWaste);
@@ -148,6 +164,8 @@
   _cur_optional_evac_ms = 0.0;
   _cur_collection_code_root_fixup_time_ms = 0.0;
   _cur_strong_code_root_purge_time_ms = 0.0;
+  _cur_merge_heap_roots_time_ms = 0.0;
+  _cur_optional_merge_heap_roots_time_ms = 0.0;
   _cur_evac_fail_recalc_used = 0.0;
   _cur_evac_fail_remove_self_forwards = 0.0;
   _cur_string_deduplication_time_ms = 0.0;
@@ -160,6 +178,7 @@
   _cur_collection_start_sec = 0.0;
   _root_region_scan_wait_time_ms = 0.0;
   _external_accounted_time_ms = 0.0;
+  _recorded_prepare_heap_roots_time_ms = 0.0;
   _recorded_clear_claimed_marks_time_ms = 0.0;
   _recorded_young_cset_choice_time_ms = 0.0;
   _recorded_non_young_cset_choice_time_ms = 0.0;
@@ -219,9 +238,7 @@
       record_time_secs(GCWorkerTotal, i , total_worker_time);
 
       double worker_known_time = worker_time(ExtRootScan, i) +
-                                 worker_time(ScanHCC, i) +
-                                 worker_time(UpdateRS, i) +
-                                 worker_time(ScanRS, i) +
+                                 worker_time(ScanHR, i) +
                                  worker_time(CodeRoots, i) +
                                  worker_time(ObjCopy, i) +
                                  worker_time(Termination, i);
@@ -231,11 +248,15 @@
       // Make sure all slots are uninitialized since this thread did not seem to have been started
       ASSERT_PHASE_UNINITIALIZED(GCWorkerEnd);
       ASSERT_PHASE_UNINITIALIZED(ExtRootScan);
-      ASSERT_PHASE_UNINITIALIZED(ScanHCC);
-      ASSERT_PHASE_UNINITIALIZED(UpdateRS);
-      ASSERT_PHASE_UNINITIALIZED(ScanRS);
+      ASSERT_PHASE_UNINITIALIZED(MergeHCC);
+      ASSERT_PHASE_UNINITIALIZED(MergeRS);
+      ASSERT_PHASE_UNINITIALIZED(OptMergeRS);
+      ASSERT_PHASE_UNINITIALIZED(MergeLB);
+      ASSERT_PHASE_UNINITIALIZED(ScanHR);
       ASSERT_PHASE_UNINITIALIZED(CodeRoots);
+      ASSERT_PHASE_UNINITIALIZED(OptCodeRoots);
       ASSERT_PHASE_UNINITIALIZED(ObjCopy);
+      ASSERT_PHASE_UNINITIALIZED(OptObjCopy);
       ASSERT_PHASE_UNINITIALIZED(Termination);
     }
   }
@@ -365,6 +386,7 @@
                         _recorded_young_cset_choice_time_ms +
                         _recorded_non_young_cset_choice_time_ms +
                         _cur_region_register_time +
+                        _recorded_prepare_heap_roots_time_ms +
                         _recorded_clear_claimed_marks_time_ms;
 
   info_time("Pre Evacuate Collection Set", sum_ms);
@@ -380,6 +402,7 @@
     trace_count("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
   }
 
+  debug_time("Prepare Heap Roots", _recorded_prepare_heap_roots_time_ms);
   if (_recorded_clear_claimed_marks_time_ms > 0.0) {
     debug_time("Clear Claimed Marks", _recorded_clear_claimed_marks_time_ms);
   }
@@ -387,10 +410,13 @@
 }
 
 double G1GCPhaseTimes::print_evacuate_optional_collection_set() const {
-  const double sum_ms = _cur_optional_evac_ms;
+  const double sum_ms = _cur_optional_evac_ms + _cur_optional_merge_heap_roots_time_ms;
   if (sum_ms > 0) {
-    info_time("Evacuate Optional Collection Set", sum_ms);
-    debug_phase(_gc_par_phases[OptScanRS]);
+    info_time("Merge Optional Heap Roots", _cur_optional_merge_heap_roots_time_ms);
+    debug_phase(_gc_par_phases[OptMergeRS]);
+
+    info_time("Evacuate Optional Collection Set", _cur_optional_evac_ms);
+    debug_phase(_gc_par_phases[OptScanHR]);
     debug_phase(_gc_par_phases[OptObjCopy]);
     debug_phase(_gc_par_phases[OptCodeRoots]);
     debug_phase(_gc_par_phases[OptTermination]);
@@ -398,21 +424,23 @@
   return sum_ms;
 }
 
-double G1GCPhaseTimes::print_evacuate_collection_set() const {
-  const double sum_ms = _cur_collection_initial_evac_time_ms;
+double G1GCPhaseTimes::print_evacuate_initial_collection_set() const {
+  info_time("Merge Heap Roots", _cur_merge_heap_roots_time_ms);
 
-  info_time("Evacuate Collection Set", sum_ms);
+  debug_phase(_gc_par_phases[MergeRS]);
+  if (G1HotCardCache::default_use_cache()) {
+    debug_phase(_gc_par_phases[MergeHCC]);
+  }
+  debug_phase(_gc_par_phases[MergeLB]);
+
+  info_time("Evacuate Collection Set", _cur_collection_initial_evac_time_ms);
 
   trace_phase(_gc_par_phases[GCWorkerStart], false);
   debug_phase(_gc_par_phases[ExtRootScan]);
   for (int i = ExtRootScanSubPhasesFirst; i <= ExtRootScanSubPhasesLast; i++) {
     trace_phase(_gc_par_phases[i]);
   }
-  if (G1HotCardCache::default_use_cache()) {
-    debug_phase(_gc_par_phases[ScanHCC]);
-  }
-  debug_phase(_gc_par_phases[UpdateRS]);
-  debug_phase(_gc_par_phases[ScanRS]);
+  debug_phase(_gc_par_phases[ScanHR]);
   debug_phase(_gc_par_phases[CodeRoots]);
   debug_phase(_gc_par_phases[ObjCopy]);
   debug_phase(_gc_par_phases[Termination]);
@@ -420,7 +448,7 @@
   debug_phase(_gc_par_phases[GCWorkerTotal]);
   trace_phase(_gc_par_phases[GCWorkerEnd], false);
 
-  return sum_ms;
+  return _cur_collection_initial_evac_time_ms + _cur_merge_heap_roots_time_ms;
 }
 
 double G1GCPhaseTimes::print_post_evacuate_collection_set() const {
@@ -503,7 +531,7 @@
 
   double accounted_ms = 0.0;
   accounted_ms += print_pre_evacuate_collection_set();
-  accounted_ms += print_evacuate_collection_set();
+  accounted_ms += print_evacuate_initial_collection_set();
   accounted_ms += print_evacuate_optional_collection_set();
   accounted_ms += print_post_evacuate_collection_set();
   print_other(accounted_ms);
@@ -530,10 +558,12 @@
       "CMRefRoots",
       "WaitForStrongCLD",
       "WeakCLDRoots",
-      "UpdateRS",
-      "ScanHCC",
-      "ScanRS",
-      "OptScanRS",
+      "MergeRS",
+      "OptMergeRS",
+      "MergeLB",
+      "MergeHCC",
+      "ScanHR",
+      "OptScanHR",
       "CodeRoots",
       "OptCodeRoots",
       "ObjCopy",
@@ -580,8 +610,8 @@
   _stopped = true;
 }
 
-G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) :
-  _start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id), _event() {
+G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool must_record) :
+  _start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id), _event(), _must_record(must_record) {
   if (_phase_times != NULL) {
     _start_time = Ticks::now();
   }
@@ -589,7 +619,11 @@
 
 G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
   if (_phase_times != NULL) {
-    _phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
+    if (_must_record) {
+      _phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
+    } else {
+      _phase_times->record_or_add_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
+    }
     _event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_phase));
   }
 }
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -60,10 +60,12 @@
     CMRefRoots,
     WaitForStrongCLD,
     WeakCLDRoots,
-    UpdateRS,
-    ScanHCC,
-    ScanRS,
-    OptScanRS,
+    MergeRS,
+    OptMergeRS,
+    MergeLB,
+    MergeHCC,
+    ScanHR,
+    OptScanHR,
     CodeRoots,
     OptCodeRoots,
     ObjCopy,
@@ -84,18 +86,24 @@
   static const GCParPhases ExtRootScanSubPhasesFirst = ThreadRoots;
   static const GCParPhases ExtRootScanSubPhasesLast = WeakCLDRoots;
 
-  enum GCScanRSWorkItems {
-    ScanRSScannedCards,
-    ScanRSClaimedCards,
-    ScanRSSkippedCards,
-    ScanRSScannedOptRefs,
-    ScanRSUsedMemory
+  enum GCMergeRSWorkTimes {
+    MergeRSMergedSparse,
+    MergeRSMergedFine,
+    MergeRSMergedCoarse
   };
 
-  enum GCUpdateRSWorkItems {
-    UpdateRSProcessedBuffers,
-    UpdateRSScannedCards,
-    UpdateRSSkippedCards
+  enum GCScanHRWorkItems {
+    ScanHRScannedCards,
+    ScanHRScannedBlocks,
+    ScanHRClaimedChunks,
+    ScanHRScannedOptRefs,
+    ScanHRUsedMemory
+  };
+
+  enum GCMergeLBWorkItems {
+    MergeLBProcessedBuffers,
+    MergeLBDirtyCards,
+    MergeLBSkippedCards
   };
 
   enum GCObjCopyWorkItems {
@@ -109,19 +117,27 @@
 
   WorkerDataArray<double>* _gc_par_phases[GCParPhasesSentinel];
 
-  WorkerDataArray<size_t>* _update_rs_processed_buffers;
-  WorkerDataArray<size_t>* _update_rs_scanned_cards;
-  WorkerDataArray<size_t>* _update_rs_skipped_cards;
+  WorkerDataArray<size_t>* _merge_rs_merged_sparse;
+  WorkerDataArray<size_t>* _merge_rs_merged_fine;
+  WorkerDataArray<size_t>* _merge_rs_merged_coarse;
+
+  WorkerDataArray<size_t>* _merge_lb_processed_buffers;
+  WorkerDataArray<size_t>* _merge_lb_dirty_cards;
+  WorkerDataArray<size_t>* _merge_lb_skipped_cards;
 
-  WorkerDataArray<size_t>* _scan_rs_scanned_cards;
-  WorkerDataArray<size_t>* _scan_rs_claimed_cards;
-  WorkerDataArray<size_t>* _scan_rs_skipped_cards;
+  WorkerDataArray<size_t>* _scan_hr_scanned_cards;
+  WorkerDataArray<size_t>* _scan_hr_scanned_blocks;
+  WorkerDataArray<size_t>* _scan_hr_claimed_chunks;
 
-  WorkerDataArray<size_t>* _opt_scan_rs_scanned_cards;
-  WorkerDataArray<size_t>* _opt_scan_rs_claimed_cards;
-  WorkerDataArray<size_t>* _opt_scan_rs_skipped_cards;
-  WorkerDataArray<size_t>* _opt_scan_rs_scanned_opt_refs;
-  WorkerDataArray<size_t>* _opt_scan_rs_used_memory;
+  WorkerDataArray<size_t>* _opt_merge_rs_merged_sparse;
+  WorkerDataArray<size_t>* _opt_merge_rs_merged_fine;
+  WorkerDataArray<size_t>* _opt_merge_rs_merged_coarse;
+
+  WorkerDataArray<size_t>* _opt_scan_hr_scanned_cards;
+  WorkerDataArray<size_t>* _opt_scan_hr_scanned_blocks;
+  WorkerDataArray<size_t>* _opt_scan_hr_claimed_chunks;
+  WorkerDataArray<size_t>* _opt_scan_hr_scanned_opt_refs;
+  WorkerDataArray<size_t>* _opt_scan_hr_used_memory;
 
   WorkerDataArray<size_t>* _obj_copy_lab_waste;
   WorkerDataArray<size_t>* _obj_copy_lab_undo_waste;
@@ -145,6 +161,9 @@
 
   double _cur_string_deduplication_time_ms;
 
+  double _cur_merge_heap_roots_time_ms;
+  double _cur_optional_merge_heap_roots_time_ms;
+
   double _cur_prepare_tlab_time_ms;
   double _cur_resize_tlab_time_ms;
 
@@ -159,6 +178,8 @@
 
   double _external_accounted_time_ms;
 
+  double _recorded_prepare_heap_roots_time_ms;
+
   double _recorded_clear_claimed_marks_time_ms;
 
   double _recorded_young_cset_choice_time_ms;
@@ -208,7 +229,8 @@
   void trace_count(const char* name, size_t value) const;
 
   double print_pre_evacuate_collection_set() const;
-  double print_evacuate_collection_set() const;
+  double print_merge_heap_roots_time() const;
+  double print_evacuate_initial_collection_set() const;
   double print_evacuate_optional_collection_set() const;
   double print_post_evacuate_collection_set() const;
   void print_other(double accounted_ms) const;
@@ -278,6 +300,14 @@
     _cur_strong_code_root_purge_time_ms = ms;
   }
 
+  void record_merge_heap_roots_time(double ms) {
+    _cur_merge_heap_roots_time_ms += ms;
+  }
+
+  void record_or_add_optional_merge_heap_roots_time(double ms) {
+    _cur_optional_merge_heap_roots_time_ms += ms;
+  }
+
   void record_evac_fail_recalc_used_time(double ms) {
     _cur_evac_fail_recalc_used = ms;
   }
@@ -357,6 +387,10 @@
     _external_accounted_time_ms += time_ms;
   }
 
+  void record_prepare_heap_roots_time_ms(double recorded_prepare_heap_roots_time_ms) {
+    _recorded_prepare_heap_roots_time_ms = recorded_prepare_heap_roots_time_ms;
+  }
+
   void record_clear_claimed_marks_time_ms(double recorded_clear_claimed_marks_time_ms) {
     _recorded_clear_claimed_marks_time_ms = recorded_clear_claimed_marks_time_ms;
   }
@@ -397,6 +431,10 @@
     return _cur_fast_reclaim_humongous_time_ms;
   }
 
+  size_t fast_reclaim_humongous_candidates() const {
+    return _cur_fast_reclaim_humongous_candidates;
+  }
+
   ReferenceProcessorPhaseTimes* ref_phase_times() { return &_ref_phase_times; }
 
   WeakProcessorPhaseTimes* weak_phase_times() { return &_weak_phase_times; }
@@ -424,8 +462,10 @@
   G1GCPhaseTimes* _phase_times;
   uint _worker_id;
   EventGCPhaseParallel _event;
+  bool _must_record;
+
 public:
-  G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id);
+  G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id, bool must_record = true);
   virtual ~G1GCParPhaseTimesTracker();
 };
 
--- a/src/hotspot/share/gc/g1/g1HeterogeneousHeapPolicy.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1HeterogeneousHeapPolicy.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -39,8 +39,8 @@
 }
 
 // After a collection pause, young list target length is updated. So we need to make sure we have enough regions in dram for young gen.
-void G1HeterogeneousHeapPolicy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc) {
-  G1Policy::record_collection_pause_end(pause_time_ms, cards_scanned, heap_used_bytes_before_gc);
+void G1HeterogeneousHeapPolicy::record_collection_pause_end(double pause_time_ms, size_t heap_used_bytes_before_gc) {
+  G1Policy::record_collection_pause_end(pause_time_ms, heap_used_bytes_before_gc);
   _manager->adjust_dram_regions((uint)young_list_target_length(), G1CollectedHeap::heap()->workers());
 }
 
--- a/src/hotspot/share/gc/g1/g1HeterogeneousHeapPolicy.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1HeterogeneousHeapPolicy.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,7 @@
   // initialize policy
   virtual void init(G1CollectedHeap* g1h, G1CollectionSet* collection_set);
   // Record end of an evacuation pause.
-  virtual void record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc);
+  virtual void record_collection_pause_end(double pause_time_ms, size_t heap_used_bytes_before_gc);
   // Record the end of full collection.
   virtual void record_full_collection_end();
 
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -51,6 +51,7 @@
     _tenuring_threshold(g1h->policy()->tenuring_threshold()),
     _scanner(g1h, this),
     _worker_id(worker_id),
+    _last_enqueued_card(SIZE_MAX),
     _stack_trim_upper_threshold(GCDrainStackTargetSize * 2 + 1),
     _stack_trim_lower_threshold(GCDrainStackTargetSize),
     _trim_ticks(),
@@ -371,7 +372,7 @@
     }
 
     size_t used_memory = pss->oops_into_optional_region(hr)->used_memory();
-    _g1h->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_index, used_memory, G1GCPhaseTimes::ScanRSUsedMemory);
+    _g1h->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanHR, worker_index, used_memory, G1GCPhaseTimes::ScanHRUsedMemory);
   }
 }
 
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -60,6 +60,10 @@
 
   uint _worker_id;
 
+  // Remember the last enqueued card to avoid enqueuing the same card over and over;
+  // since we only ever scan a card once, this is sufficient.
+  size_t _last_enqueued_card;
+
   // Upper and lower threshold to start and end work queue draining.
   uint const _stack_trim_upper_threshold;
   uint const _stack_trim_lower_threshold;
@@ -128,8 +132,9 @@
     }
     size_t card_index = ct()->index_for(p);
     // If the card hasn't been added to the buffer, do it.
-    if (ct()->mark_card_deferred(card_index)) {
+    if (_last_enqueued_card != card_index) {
       dirty_card_queue().enqueue(ct()->byte_for_index(card_index));
+      _last_enqueued_card = card_index;
     }
   }
 
--- a/src/hotspot/share/gc/g1/g1Policy.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -572,10 +572,24 @@
   return result;
 }
 
+double G1Policy::log_buffer_processing_time() const {
+  double all_cards_processing_time = average_time_ms(G1GCPhaseTimes::ScanHR) + average_time_ms(G1GCPhaseTimes::OptScanHR);
+  size_t log_buffer_dirty_cards = phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards);
+  size_t scan_heap_roots_cards = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) +
+                                 phase_times()->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards);
+  // This may happen if there are duplicate cards in different log buffers.
+  if (log_buffer_dirty_cards > scan_heap_roots_cards) {
+    return all_cards_processing_time + average_time_ms(G1GCPhaseTimes::MergeLB);
+  }
+  return (all_cards_processing_time * log_buffer_dirty_cards / scan_heap_roots_cards) + average_time_ms(G1GCPhaseTimes::MergeLB);
+}
+
 // Anything below that is considered to be zero
 #define MIN_TIMER_GRANULARITY 0.0000001
 
-void G1Policy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc) {
+void G1Policy::record_collection_pause_end(double pause_time_ms, size_t heap_used_bytes_before_gc) {
+  G1GCPhaseTimes* p = phase_times();
+
   double end_time_sec = os::elapsedTime();
 
   assert_used_and_recalculate_used_equal(_g1h);
@@ -645,29 +659,40 @@
   _short_lived_surv_rate_group->start_adding_regions();
   // Do that for any other surv rate groups
 
-  double scan_hcc_time_ms = G1HotCardCache::default_use_cache() ? average_time_ms(G1GCPhaseTimes::ScanHCC) : 0.0;
+  double scan_hcc_time_ms = G1HotCardCache::default_use_cache() ? average_time_ms(G1GCPhaseTimes::MergeHCC) : 0.0;
 
   if (update_stats) {
-    double cost_per_card_ms = 0.0;
-    if (_pending_cards > 0) {
-      cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS)) / (double) _pending_cards;
-      _analytics->report_cost_per_card_ms(cost_per_card_ms);
+    double cost_per_log_buffer_entry = 0.0;
+    size_t const pending_log_buffer_entries = p->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards);
+    if (pending_log_buffer_entries > 0) {
+      cost_per_log_buffer_entry = log_buffer_processing_time() / pending_log_buffer_entries;
+      _analytics->report_cost_per_log_buffer_entry_ms(cost_per_log_buffer_entry);
     }
     _analytics->report_cost_scan_hcc(scan_hcc_time_ms);
 
-    double cost_per_entry_ms = 0.0;
-    if (cards_scanned > 10) {
-      double avg_time_scan_rs = average_time_ms(G1GCPhaseTimes::ScanRS);
-      if (this_pause_was_young_only) {
-        avg_time_scan_rs += average_time_ms(G1GCPhaseTimes::OptScanRS);
-      }
-      cost_per_entry_ms = avg_time_scan_rs / cards_scanned;
-      _analytics->report_cost_per_entry_ms(cost_per_entry_ms, this_pause_was_young_only);
+    size_t const total_cards_scanned = p->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) +
+                                       p->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards);
+    size_t remset_cards_scanned = 0;
+    // There might have been duplicate log buffer entries in the queues which could
+    // increase this value beyond the cards scanned. In this case attribute all cards
+    // to the log buffers.
+    if (pending_log_buffer_entries <= total_cards_scanned) {
+      remset_cards_scanned = total_cards_scanned - pending_log_buffer_entries;
+    }
+
+    double cost_per_remset_card_ms = 0.0;
+    if (remset_cards_scanned > 10) {
+      double avg_time_remset_scan = ((average_time_ms(G1GCPhaseTimes::ScanHR) + average_time_ms(G1GCPhaseTimes::OptScanHR)) *
+                                     remset_cards_scanned / total_cards_scanned) +
+                                    average_time_ms(G1GCPhaseTimes::MergeRS);
+
+      cost_per_remset_card_ms = avg_time_remset_scan / remset_cards_scanned;
+      _analytics->report_cost_per_remset_card_ms(cost_per_remset_card_ms, this_pause_was_young_only);
     }
 
     if (_max_rs_lengths > 0) {
       double cards_per_entry_ratio =
-        (double) cards_scanned / (double) _max_rs_lengths;
+        (double) remset_cards_scanned / (double) _max_rs_lengths;
       _analytics->report_cards_per_entry_ratio(cards_per_entry_ratio, this_pause_was_young_only);
     }
 
@@ -759,20 +784,26 @@
   }
 
   // Note that _mmu_tracker->max_gc_time() returns the time in seconds.
-  double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0;
+  double scan_log_buffer_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0;
 
-  if (update_rs_time_goal_ms < scan_hcc_time_ms) {
+  if (scan_log_buffer_time_goal_ms < scan_hcc_time_ms) {
     log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)."
-                                "Update RS time goal: %1.2fms Scan HCC time: %1.2fms",
-                                update_rs_time_goal_ms, scan_hcc_time_ms);
+                                "Log Buffer Scan time goal: %1.2fms Scan HCC time: %1.2fms",
+                                scan_log_buffer_time_goal_ms, scan_hcc_time_ms);
 
-    update_rs_time_goal_ms = 0;
+    scan_log_buffer_time_goal_ms = 0;
   } else {
-    update_rs_time_goal_ms -= scan_hcc_time_ms;
+    scan_log_buffer_time_goal_ms -= scan_hcc_time_ms;
   }
-  _g1h->concurrent_refine()->adjust(average_time_ms(G1GCPhaseTimes::UpdateRS),
-                                    phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS),
-                                    update_rs_time_goal_ms);
+
+  double const log_buffer_time = log_buffer_processing_time();
+
+  log_debug(gc, ergo, refine)("Concurrent refinement times: Log Buffer Scan time goal: %1.2fms Log Buffer Scan time: %1.2fms HCC time: %1.2fms",
+                              scan_log_buffer_time_goal_ms, log_buffer_time, scan_hcc_time_ms);
+
+  _g1h->concurrent_refine()->adjust(log_buffer_time,
+                                    phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBProcessedBuffers),
+                                    scan_log_buffer_time_goal_ms);
 }
 
 G1IHOPControl* G1Policy::create_ihop_control(const G1Predictions* predictor){
--- a/src/hotspot/share/gc/g1/g1Policy.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -111,6 +111,8 @@
   bool should_update_surv_rate_group_predictors() {
     return collector_state()->in_young_only_phase() && !collector_state()->mark_or_rebuild_in_progress();
   }
+
+  double log_buffer_processing_time() const;
 public:
   const G1Predictions& predictor() const { return _predictor; }
   const G1Analytics* analytics()   const { return const_cast<const G1Analytics*>(_analytics); }
@@ -311,7 +313,7 @@
 
   // Record the start and end of an evacuation pause.
   void record_collection_pause_start(double start_time_sec);
-  virtual void record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc);
+  virtual void record_collection_pause_end(double pause_time_ms, size_t heap_used_bytes_before_gc);
 
   // Record the start and end of a full collection.
   void record_full_collection_start();
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,8 @@
 #include "gc/g1/g1SharedDirtyCardQueue.hpp"
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
-#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/heapRegionRemSet.inline.hpp"
+#include "gc/g1/sparsePRT.hpp"
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "jfr/jfrEvents.hpp"
@@ -52,40 +53,453 @@
 #include "utilities/stack.inline.hpp"
 #include "utilities/ticks.hpp"
 
-// Collects information about the overall remembered set scan progress during an evacuation.
+// Collects information about the overall heap root scan progress during an evacuation.
+//
+// Scanning the remembered sets works by first merging all sources of cards to be
+// scanned (log buffers, hcc, remembered sets) into a single data structure to remove
+// duplicates and simplify work distribution.
+//
+// During the following card scanning we not only scan this combined set of cards, but
+// also remember that these were completely scanned. The following evacuation passes
+// do not scan these cards again, and so need to be preserved across increments.
+//
+// The representation for all the cards to scan is the card table: cards can have
+// one of three states during GC:
+// - clean: these cards will not be scanned in this pass
+// - dirty: these cards will be scanned in this pass
+// - scanned: these cards have already been scanned in a previous pass
+//
+// After all evacuation is done, we reset the card table to clean.
+//
+// Work distribution occurs on "chunk" basis, i.e. contiguous ranges of cards. As an
+// additional optimization, during card merging we remember which regions and which
+// chunks actually contain cards to be scanned. Threads iterate only across these
+// regions, and only compete for chunks containing any cards.
+//
+// Within these chunks, a worker scans the card table on "blocks" of cards, i.e.
+// contiguous ranges of dirty cards to be scanned. These blocks are converted to actual
+// memory ranges and then passed on to actual scanning.
 class G1RemSetScanState : public CHeapObj<mtGC> {
+  class G1DirtyRegions;
+
+  size_t _max_regions;
+
+  // Has this region that is part of the regions in the collection set been processed yet.
+  typedef bool G1RemsetIterState;
+
+  G1RemsetIterState volatile* _collection_set_iter_state;
+
+  // Card table iteration claim for each heap region, from 0 (completely unscanned)
+  // to (>=) HeapRegion::CardsPerRegion (completely scanned).
+  uint volatile* _card_table_scan_state;
+
+  // Random power of two number of cards we want to claim per thread. This corresponds
+  // to a 64k of memory work chunk area for every thread.
+  // We use the same claim size as Parallel GC. No particular measurements have been
+  // performed to determine an optimal number.
+  static const uint CardsPerChunk = 128;
+
+  uint _scan_chunks_per_region;
+  bool* _region_scan_chunks;
+  uint8_t _scan_chunks_shift;
+public:
+  uint scan_chunk_size() const { return (uint)1 << _scan_chunks_shift; }
+
+  // Returns whether the chunk corresponding to the given region/card in region contain a
+  // dirty card, i.e. actually needs scanning.
+  bool chunk_needs_scan(uint const region_idx, uint const card_in_region) const {
+    size_t const idx = (size_t)region_idx * _scan_chunks_per_region + (card_in_region >> _scan_chunks_shift);
+    assert(idx < (_max_regions * _scan_chunks_per_region), "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT,
+           idx, _max_regions * _scan_chunks_per_region);
+    return _region_scan_chunks[idx];
+  }
+
 private:
+  // The complete set of regions which card table needs to be cleared at the end of GC because
+  // we scribbled all over them.
+  G1DirtyRegions* _all_dirty_regions;
+  // The set of regions which card table needs to be scanned for new dirty cards
+  // in the current evacuation pass.
+  G1DirtyRegions* _next_dirty_regions;
+
+  // Set of (unique) regions that can be added to concurrently.
+  class G1DirtyRegions : public CHeapObj<mtGC> {
+    uint* _buffer;
+    uint _cur_idx;
+    size_t _max_regions;
+
+    bool* _contains;
+
+  public:
+    G1DirtyRegions(size_t max_regions) :
+      _buffer(NEW_C_HEAP_ARRAY(uint, max_regions, mtGC)),
+      _cur_idx(0),
+      _max_regions(max_regions),
+      _contains(NEW_C_HEAP_ARRAY(bool, max_regions, mtGC)) {
+
+      reset();
+    }
+
+    static size_t chunk_size() { return M; }
+
+    ~G1DirtyRegions() {
+      FREE_C_HEAP_ARRAY(uint, _buffer);
+      FREE_C_HEAP_ARRAY(bool, _contains);
+    }
+
+    void reset() {
+      _cur_idx = 0;
+      ::memset(_contains, false, _max_regions * sizeof(bool));
+    }
+
+    uint size() const { return _cur_idx; }
+
+    uint at(uint idx) const {
+      assert(idx < _cur_idx, "Index %u beyond valid regions", idx);
+      return _buffer[idx];
+    }
+
+    void add_dirty_region(uint region) {
+      if (_contains[region]) {
+        return;
+      }
+
+      bool marked_as_dirty = Atomic::cmpxchg(true, &_contains[region], false) == false;
+      if (marked_as_dirty) {
+        uint allocated = Atomic::add(1u, &_cur_idx) - 1;
+        _buffer[allocated] = region;
+      }
+    }
+
+    // Creates the union of this and the other G1DirtyRegions.
+    void merge(const G1DirtyRegions* other) {
+      for (uint i = 0; i < other->size(); i++) {
+        uint region = other->at(i);
+        if (!_contains[region]) {
+          _buffer[_cur_idx++] = region;
+          _contains[region] = true;
+        }
+      }
+    }
+  };
+
+  // Returns whether the given region contains cards we need to scan. The remembered
+  // set and other sources may contain cards that
+  // - are in uncommitted regions
+  // - are located in the collection set
+  // - are located in free regions
+  // as we do not clean up remembered sets before merging heap roots.
+  bool contains_cards_to_process(uint const region_idx) const {
+    HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx);
+    return (hr != NULL && !hr->in_collection_set() && hr->is_old_or_humongous_or_archive());
+  }
+
+  class G1MergeCardSetClosure : public HeapRegionClosure {
+    G1RemSetScanState* _scan_state;
+    G1CardTable* _ct;
+
+    uint _merged_sparse;
+    uint _merged_fine;
+    uint _merged_coarse;
+
+    // Returns if the region contains cards we need to scan. If so, remember that
+    // region in the current set of dirty regions.
+    bool remember_if_interesting(uint const region_idx) {
+      if (!_scan_state->contains_cards_to_process(region_idx)) {
+        return false;
+      }
+      _scan_state->add_dirty_region(region_idx);
+      return true;
+    }
+  public:
+    G1MergeCardSetClosure(G1RemSetScanState* scan_state) :
+      _scan_state(scan_state),
+      _ct(G1CollectedHeap::heap()->card_table()),
+      _merged_sparse(0),
+      _merged_fine(0),
+      _merged_coarse(0) { }
+
+    void next_coarse_prt(uint const region_idx) {
+      if (!remember_if_interesting(region_idx)) {
+        return;
+      }
+
+      _merged_coarse++;
+
+      size_t region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
+      _ct->mark_region_dirty(region_base_idx, HeapRegion::CardsPerRegion);
+      _scan_state->set_chunk_region_dirty(region_base_idx);
+    }
+
+    void next_fine_prt(uint const region_idx, BitMap* bm) {
+      if (!remember_if_interesting(region_idx)) {
+        return;
+      }
+
+      _merged_fine++;
+
+      size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
+      BitMap::idx_t cur = bm->get_next_one_offset(0);
+      while (cur != bm->size()) {
+        _ct->mark_clean_as_dirty(region_base_idx + cur);
+        _scan_state->set_chunk_dirty(region_base_idx + cur);
+        cur = bm->get_next_one_offset(cur + 1);
+      }
+    }
+
+    void next_sparse_prt(uint const region_idx, SparsePRTEntry::card_elem_t* cards, uint const num_cards) {
+      if (!remember_if_interesting(region_idx)) {
+        return;
+      }
+
+      _merged_sparse++;
+
+      size_t const region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion;
+      for (uint i = 0; i < num_cards; i++) {
+        size_t card_idx = region_base_idx + cards[i];
+        _ct->mark_clean_as_dirty(card_idx);
+        _scan_state->set_chunk_dirty(card_idx);
+      }
+    }
+
+    virtual bool do_heap_region(HeapRegion* r) {
+      assert(r->in_collection_set() || r->is_starts_humongous(), "must be");
+
+      HeapRegionRemSet* rem_set = r->rem_set();
+      if (!rem_set->is_empty()) {
+        rem_set->iterate_prts(*this);
+      }
+
+      return false;
+    }
+
+    size_t merged_sparse() const { return _merged_sparse; }
+    size_t merged_fine() const { return _merged_fine; }
+    size_t merged_coarse() const { return _merged_coarse; }
+  };
+
+  // Visitor for the remembered sets of humongous candidate regions to merge their
+  // remembered set into the card table.
+  class G1FlushHumongousCandidateRemSets : public HeapRegionClosure {
+    G1MergeCardSetClosure _cl;
+
+  public:
+    G1FlushHumongousCandidateRemSets(G1RemSetScanState* scan_state) : _cl(scan_state) { }
+
+    virtual bool do_heap_region(HeapRegion* r) {
+      G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+      if (!r->is_starts_humongous() ||
+          !g1h->region_attr(r->hrm_index()).is_humongous() ||
+          r->rem_set()->is_empty()) {
+        return false;
+      }
+
+      guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
+                "Found a not-small remembered set here. This is inconsistent with previous assumptions.");
+
+      _cl.do_heap_region(r);
+
+      // We should only clear the card based remembered set here as we will not
+      // implicitly rebuild anything else during eager reclaim. Note that at the moment
+      // (and probably never) we do not enter this path if there are other kind of
+      // remembered sets for this region.
+      r->rem_set()->clear_locked(true /* only_cardset */);
+      // Clear_locked() above sets the state to Empty. However we want to continue
+      // collecting remembered set entries for humongous regions that were not
+      // reclaimed.
+      r->rem_set()->set_state_complete();
+#ifdef ASSERT
+      G1HeapRegionAttr region_attr = g1h->region_attr(r->hrm_index());
+      assert(region_attr.needs_remset_update(), "must be");
+#endif
+      assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
+
+      return false;
+    }
+
+    size_t merged_sparse() const { return _cl.merged_sparse(); }
+    size_t merged_fine() const { return _cl.merged_fine(); }
+    size_t merged_coarse() const { return _cl.merged_coarse(); }
+  };
+
+  // Visitor for the log buffer entries to merge them into the card table.
+  class G1MergeLogBufferCardsClosure : public G1CardTableEntryClosure {
+    G1RemSetScanState* _scan_state;
+    G1CardTable* _ct;
+
+    size_t _cards_dirty;
+    size_t _cards_skipped;
+  public:
+    G1MergeLogBufferCardsClosure(G1CollectedHeap* g1h, G1RemSetScanState* scan_state) :
+      _scan_state(scan_state), _ct(g1h->card_table()), _cards_dirty(0), _cards_skipped(0)
+    {}
+
+    bool do_card_ptr(CardValue* card_ptr, uint worker_i) {
+      // The only time we care about recording cards that
+      // contain references that point into the collection set
+      // is during RSet updating within an evacuation pause.
+      // In this case worker_id should be the id of a GC worker thread.
+      assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
+
+      uint const region_idx = _ct->region_idx_for(card_ptr);
+
+      // The second clause must come after - the log buffers might contain cards to uncommited
+      // regions.
+      // This code may count duplicate entries in the log buffers (even if rare) multiple
+      // times.
+      if (_scan_state->contains_cards_to_process(region_idx) && (*card_ptr == G1CardTable::dirty_card_val())) {
+        _scan_state->add_dirty_region(region_idx);
+        _scan_state->set_chunk_dirty(_ct->index_for_cardvalue(card_ptr));
+        _cards_dirty++;
+      } else {
+        // We may have had dirty cards in the (initial) collection set (or the
+        // young regions which are always in the initial collection set). We do
+        // not fix their cards here: we already added these regions to the set of
+        // regions to clear the card table at the end during the prepare() phase.
+        _cards_skipped++;
+      }
+      return true;
+    }
+
+    size_t cards_dirty() const { return _cards_dirty; }
+    size_t cards_skipped() const { return _cards_skipped; }
+  };
+
+  class G1MergeHeapRootsTask : public AbstractGangTask {
+    HeapRegionClaimer _hr_claimer;
+    G1RemSetScanState* _scan_state;
+    bool _remembered_set_only;
+
+    G1GCPhaseTimes::GCParPhases _merge_phase;
+
+    volatile bool _fast_reclaim_handled;
+
+  public:
+    G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) :
+      AbstractGangTask("G1 Merge Heap Roots"),
+      _hr_claimer(num_workers),
+      _scan_state(scan_state),
+      _remembered_set_only(remembered_set_only),
+      _merge_phase(merge_phase),
+      _fast_reclaim_handled(false) { }
+
+    virtual void work(uint worker_id) {
+      G1CollectedHeap* g1h = G1CollectedHeap::heap();
+      G1GCPhaseTimes* p = g1h->phase_times();
+
+      // We schedule flushing the remembered sets of humongous fast reclaim candidates
+      // onto the card table first to allow the remaining parallelized tasks hide it.
+      if (!_remembered_set_only &&
+          p->fast_reclaim_humongous_candidates() > 0 &&
+          !_fast_reclaim_handled &&
+          !Atomic::cmpxchg(true, &_fast_reclaim_handled, false)) {
+
+        G1FlushHumongousCandidateRemSets cl(_scan_state);
+        g1h->heap_region_iterate(&cl);
+
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
+      }
+
+      // Merge remembered sets of current candidates.
+      {
+        G1GCParPhaseTimesTracker x(p, _merge_phase, worker_id, !_remembered_set_only /* must_record */);
+        G1MergeCardSetClosure cl(_scan_state);
+        g1h->collection_set_iterate_increment_from(&cl, &_hr_claimer, worker_id);
+
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_sparse(), G1GCPhaseTimes::MergeRSMergedSparse);
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_fine(), G1GCPhaseTimes::MergeRSMergedFine);
+        p->record_or_add_thread_work_item(_merge_phase, worker_id, cl.merged_coarse(), G1GCPhaseTimes::MergeRSMergedCoarse);
+      }
+
+      // Apply closure to log entries in the HCC.
+      if (!_remembered_set_only && G1HotCardCache::default_use_cache()) {
+        assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
+        G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id);
+        G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
+        g1h->iterate_hcc_closure(&cl, worker_id);
+      }
+
+      // Now apply the closure to all remaining log entries.
+      if (!_remembered_set_only) {
+        assert(_merge_phase == G1GCPhaseTimes::MergeRS, "Wrong merge phase");
+        G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeLB, worker_id);
+
+        G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
+        g1h->iterate_dirty_card_closure(&cl, worker_id);
+
+        p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeLBDirtyCards);
+        p->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeLBSkippedCards);
+      }
+    }
+  };
+
+  // Creates a snapshot of the current _top values at the start of collection to
+  // filter out card marks that we do not want to scan.
+  class G1ResetScanTopClosure : public HeapRegionClosure {
+    G1RemSetScanState* _scan_state;
+
+  public:
+    G1ResetScanTopClosure(G1RemSetScanState* scan_state) : _scan_state(scan_state) { }
+
+    virtual bool do_heap_region(HeapRegion* r) {
+      uint hrm_index = r->hrm_index();
+      if (r->in_collection_set()) {
+        // Young regions had their card table marked as young at their allocation;
+        // we need to make sure that these marks are cleared at the end of GC, *but*
+        // they should not be scanned for cards.
+        // So directly add them to the "all_dirty_regions".
+        // Same for regions in the (initial) collection set: they may contain cards from
+        // the log buffers, make sure they are cleaned.
+        _scan_state->add_all_dirty_region(hrm_index);
+       } else if (r->is_old_or_humongous_or_archive()) {
+        _scan_state->set_scan_top(hrm_index, r->top());
+       }
+       return false;
+     }
+  };
+  // For each region, contains the maximum top() value to be used during this garbage
+  // collection. Subsumes common checks like filtering out everything but old and
+  // humongous regions outside the collection set.
+  // This is valid because we are not interested in scanning stray remembered set
+  // entries from free or archive regions.
+  HeapWord** _scan_top;
+
   class G1ClearCardTableTask : public AbstractGangTask {
     G1CollectedHeap* _g1h;
-    uint* _dirty_region_list;
-    size_t _num_dirty_regions;
-    size_t _chunk_length;
+    G1DirtyRegions* _regions;
+    uint _chunk_length;
 
-    size_t volatile _cur_dirty_regions;
+    uint volatile _cur_dirty_regions;
+
+    G1RemSetScanState* _scan_state;
+
   public:
     G1ClearCardTableTask(G1CollectedHeap* g1h,
-                         uint* dirty_region_list,
-                         size_t num_dirty_regions,
-                         size_t chunk_length) :
+                         G1DirtyRegions* regions,
+                         uint chunk_length,
+                         G1RemSetScanState* scan_state) :
       AbstractGangTask("G1 Clear Card Table Task"),
       _g1h(g1h),
-      _dirty_region_list(dirty_region_list),
-      _num_dirty_regions(num_dirty_regions),
+      _regions(regions),
       _chunk_length(chunk_length),
-      _cur_dirty_regions(0) {
+      _cur_dirty_regions(0),
+      _scan_state(scan_state) {
 
       assert(chunk_length > 0, "must be");
     }
 
-    static size_t chunk_size() { return M; }
+    static uint chunk_size() { return M; }
 
     void work(uint worker_id) {
-      while (_cur_dirty_regions < _num_dirty_regions) {
-        size_t next = Atomic::add(_chunk_length, &_cur_dirty_regions) - _chunk_length;
-        size_t max = MIN2(next + _chunk_length, _num_dirty_regions);
+      while (_cur_dirty_regions < _regions->size()) {
+        uint next = Atomic::add(_chunk_length, &_cur_dirty_regions) - _chunk_length;
+        uint max = MIN2(next + _chunk_length, _regions->size());
 
-        for (size_t i = next; i < max; i++) {
-          HeapRegion* r = _g1h->region_at(_dirty_region_list[i]);
+        for (uint i = next; i < max; i++) {
+          HeapRegion* r = _g1h->region_at(_regions->at(i));
           if (!r->is_survivor()) {
             r->clear_cardtable();
           }
@@ -94,159 +508,222 @@
     }
   };
 
-  size_t _max_regions;
-
-  // Scan progress for the remembered set of a single region. Transitions from
-  // Unclaimed -> Claimed -> Complete.
-  // At each of the transitions the thread that does the transition needs to perform
-  // some special action once. This is the reason for the extra "Claimed" state.
-  typedef jint G1RemsetIterState;
-
-  static const G1RemsetIterState Unclaimed = 0; // The remembered set has not been scanned yet.
-  static const G1RemsetIterState Claimed = 1;   // The remembered set is currently being scanned.
-  static const G1RemsetIterState Complete = 2;  // The remembered set has been completely scanned.
+  // Clear the card table of "dirty" regions.
+  void clear_card_table(WorkGang* workers) {
+    uint num_regions = _all_dirty_regions->size();
 
-  G1RemsetIterState volatile* _iter_states;
-  // The current location where the next thread should continue scanning in a region's
-  // remembered set.
-  size_t volatile* _iter_claims;
+    if (num_regions == 0) {
+      return;
+    }
 
-  // Temporary buffer holding the regions we used to store remembered set scan duplicate
-  // information. These are also called "dirty". Valid entries are from [0.._cur_dirty_region)
-  uint* _dirty_region_buffer;
-
-  // Flag for every region whether it is in the _dirty_region_buffer already
-  // to avoid duplicates.
-  bool volatile* _in_dirty_region_buffer;
-  size_t _cur_dirty_region;
+    uint const num_chunks = (uint)(align_up((size_t)num_regions << HeapRegion::LogCardsPerRegion, G1ClearCardTableTask::chunk_size()) / G1ClearCardTableTask::chunk_size());
+    uint const num_workers = MIN2(num_chunks, workers->active_workers());
+    uint const chunk_length = G1ClearCardTableTask::chunk_size() / (uint)HeapRegion::CardsPerRegion;
 
-  // Creates a snapshot of the current _top values at the start of collection to
-  // filter out card marks that we do not want to scan.
-  class G1ResetScanTopClosure : public HeapRegionClosure {
-  private:
-    HeapWord** _scan_top;
-  public:
-    G1ResetScanTopClosure(HeapWord** scan_top) : _scan_top(scan_top) { }
+    // Iterate over the dirty cards region list.
+    G1ClearCardTableTask cl(G1CollectedHeap::heap(), _all_dirty_regions, chunk_length, this);
 
-    virtual bool do_heap_region(HeapRegion* r) {
-      uint hrm_index = r->hrm_index();
-      if (!r->in_collection_set() && r->is_old_or_humongous_or_archive() && !r->is_empty()) {
-        _scan_top[hrm_index] = r->top();
-      } else {
-        _scan_top[hrm_index] = NULL;
-      }
-      return false;
-    }
-  };
+    log_debug(gc, ergo)("Running %s using %u workers for %u "
+                        "units of work for %u regions.",
+                        cl.name(), num_workers, num_chunks, num_regions);
+    workers->run_task(&cl, num_workers);
 
-  // For each region, contains the maximum top() value to be used during this garbage
-  // collection. Subsumes common checks like filtering out everything but old and
-  // humongous regions outside the collection set.
-  // This is valid because we are not interested in scanning stray remembered set
-  // entries from free or archive regions.
-  HeapWord** _scan_top;
+#ifndef PRODUCT
+    G1CollectedHeap::heap()->verifier()->verify_card_table_cleanup();
+#endif
+  }
+
 public:
   G1RemSetScanState() :
     _max_regions(0),
-    _iter_states(NULL),
-    _iter_claims(NULL),
-    _dirty_region_buffer(NULL),
-    _in_dirty_region_buffer(NULL),
-    _cur_dirty_region(0),
+    _collection_set_iter_state(NULL),
+    _card_table_scan_state(NULL),
+    _scan_chunks_per_region((uint)(HeapRegion::CardsPerRegion / CardsPerChunk)),
+    _region_scan_chunks(NULL),
+    _scan_chunks_shift(0),
+    _all_dirty_regions(NULL),
+    _next_dirty_regions(NULL),
     _scan_top(NULL) {
   }
 
   ~G1RemSetScanState() {
-    if (_iter_states != NULL) {
-      FREE_C_HEAP_ARRAY(G1RemsetIterState, _iter_states);
-    }
-    if (_iter_claims != NULL) {
-      FREE_C_HEAP_ARRAY(size_t, _iter_claims);
-    }
-    if (_dirty_region_buffer != NULL) {
-      FREE_C_HEAP_ARRAY(uint, _dirty_region_buffer);
-    }
-    if (_in_dirty_region_buffer != NULL) {
-      FREE_C_HEAP_ARRAY(bool, _in_dirty_region_buffer);
-    }
-    if (_scan_top != NULL) {
-      FREE_C_HEAP_ARRAY(HeapWord*, _scan_top);
-    }
+    FREE_C_HEAP_ARRAY(G1RemsetIterState, _collection_set_iter_state);
+    FREE_C_HEAP_ARRAY(uint, _card_table_scan_state);
+    FREE_C_HEAP_ARRAY(bool, _region_scan_chunks);
+    FREE_C_HEAP_ARRAY(HeapWord*, _scan_top);
   }
 
-  void initialize(uint max_regions) {
-    assert(_iter_states == NULL, "Must not be initialized twice");
-    assert(_iter_claims == NULL, "Must not be initialized twice");
+  void initialize(size_t max_regions) {
+    assert(_collection_set_iter_state == NULL, "Must not be initialized twice");
     _max_regions = max_regions;
-    _iter_states = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC);
-    _iter_claims = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC);
-    _dirty_region_buffer = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC);
-    _in_dirty_region_buffer = NEW_C_HEAP_ARRAY(bool, max_regions, mtGC);
+    _collection_set_iter_state = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC);
+    _card_table_scan_state = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC);
+    _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, max_regions * _scan_chunks_per_region, mtGC);
+
+    _scan_chunks_shift = (uint8_t)log2_intptr(HeapRegion::CardsPerRegion / _scan_chunks_per_region);
     _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC);
   }
 
-  void reset() {
-    for (uint i = 0; i < _max_regions; i++) {
-      _iter_states[i] = Unclaimed;
-      clear_scan_top(i);
+  void prepare() {
+    for (size_t i = 0; i < _max_regions; i++) {
+      _collection_set_iter_state[i] = false;
+      clear_scan_top((uint)i);
     }
 
-    G1ResetScanTopClosure cl(_scan_top);
+    _all_dirty_regions = new G1DirtyRegions(_max_regions);
+
+    G1ResetScanTopClosure cl(this);
     G1CollectedHeap::heap()->heap_region_iterate(&cl);
 
-    memset((void*)_iter_claims, 0, _max_regions * sizeof(size_t));
-    memset((void*)_in_dirty_region_buffer, false, _max_regions * sizeof(bool));
-    _cur_dirty_region = 0;
+    _next_dirty_regions = new G1DirtyRegions(_max_regions);
   }
 
-  // Attempt to claim the remembered set of the region for iteration. Returns true
-  // if this call caused the transition from Unclaimed to Claimed.
-  inline bool claim_iter(uint region) {
-    assert(region < _max_regions, "Tried to access invalid region %u", region);
-    if (_iter_states[region] != Unclaimed) {
-      return false;
+  void print_merge_heap_roots_stats() {
+    size_t num_scan_chunks = 0;
+    for (uint i = 0; i < _max_regions * _scan_chunks_per_region; i++) {
+      if (_region_scan_chunks[i]) {
+        num_scan_chunks++;
+      }
     }
-    G1RemsetIterState res = Atomic::cmpxchg(Claimed, &_iter_states[region], Unclaimed);
-    return (res == Unclaimed);
+    size_t num_visited_cards = num_scan_chunks * CardsPerChunk;
+    size_t total_dirty_region_cards = _next_dirty_regions->size() * HeapRegion::CardsPerRegion;
+
+    G1CollectedHeap* g1h = G1CollectedHeap::heap();
+    size_t total_old_region_cards =
+      (g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * HeapRegion::CardsPerRegion;
+
+    log_debug(gc,remset)("Visited cards " SIZE_FORMAT " Total dirty " SIZE_FORMAT " (%.2lf%%) Total old " SIZE_FORMAT " (%.2lf%%)",
+                         num_visited_cards,
+                         total_dirty_region_cards,
+                         percent_of(num_visited_cards, total_dirty_region_cards),
+                         total_old_region_cards,
+                         percent_of(num_visited_cards, total_old_region_cards));
   }
 
-  // Try to atomically sets the iteration state to "complete". Returns true for the
-  // thread that caused the transition.
-  inline bool set_iter_complete(uint region) {
-    if (iter_is_complete(region)) {
-      return false;
+  void merge_heap_roots(WorkGang* workers, bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) {
+    {
+      _all_dirty_regions->merge(_next_dirty_regions);
+      _next_dirty_regions->reset();
+      for (size_t i = 0; i < _max_regions; i++) {
+        _card_table_scan_state[i] = 0;
+      }
+
+      ::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks));
     }
-    G1RemsetIterState res = Atomic::cmpxchg(Complete, &_iter_states[region], Claimed);
-    return (res == Claimed);
+
+    size_t const increment_length = G1CollectedHeap::heap()->collection_set()->increment_length();
+
+    uint const num_workers = !remembered_set_only ? workers->active_workers() :
+                                                    MIN2(workers->active_workers(), (uint)increment_length);
+
+    {
+      G1MergeHeapRootsTask cl(this, num_workers, remembered_set_only, merge_phase);
+      log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " regions",
+                          cl.name(), num_workers, increment_length);
+      workers->run_task(&cl, num_workers);
+    }
+
+    if (log_is_enabled(Debug, gc, remset)) {
+      print_merge_heap_roots_stats();
+    }
   }
 
-  // Returns true if the region's iteration is complete.
-  inline bool iter_is_complete(uint region) const {
-    assert(region < _max_regions, "Tried to access invalid region %u", region);
-    return _iter_states[region] == Complete;
+  void set_chunk_region_dirty(size_t const region_card_idx) {
+    size_t chunk_idx = region_card_idx >> _scan_chunks_shift;
+    for (uint i = 0; i < _scan_chunks_per_region; i++) {
+      _region_scan_chunks[chunk_idx++] = true;
+    }
+  }
+
+  void set_chunk_dirty(size_t const card_idx) {
+    assert((card_idx >> _scan_chunks_shift) < (_max_regions * _scan_chunks_per_region),
+           "Trying to access index " SIZE_FORMAT " out of bounds " SIZE_FORMAT,
+           card_idx >> _scan_chunks_shift, _max_regions * _scan_chunks_per_region);
+    size_t const chunk_idx = card_idx >> _scan_chunks_shift;
+    if (!_region_scan_chunks[chunk_idx]) {
+      _region_scan_chunks[chunk_idx] = true;
+    }
   }
 
-  // The current position within the remembered set of the given region.
-  inline size_t iter_claimed(uint region) const {
-    assert(region < _max_regions, "Tried to access invalid region %u", region);
-    return _iter_claims[region];
+  void cleanup(WorkGang* workers) {
+    _all_dirty_regions->merge(_next_dirty_regions);
+
+    clear_card_table(workers);
+
+    delete _all_dirty_regions;
+    _all_dirty_regions = NULL;
+
+    delete _next_dirty_regions;
+    _next_dirty_regions = NULL;
   }
 
-  // Claim the next block of cards within the remembered set of the region with
-  // step size.
-  inline size_t iter_claimed_next(uint region, size_t step) {
-    return Atomic::add(step, &_iter_claims[region]) - step;
-  }
+  void iterate_dirty_regions_from(HeapRegionClosure* cl, uint worker_id) {
+    uint num_regions = _next_dirty_regions->size();
 
-  void add_dirty_region(uint region) {
-    if (_in_dirty_region_buffer[region]) {
+    if (num_regions == 0) {
       return;
     }
 
-    if (!Atomic::cmpxchg(true, &_in_dirty_region_buffer[region], false)) {
-      size_t allocated = Atomic::add(1u, &_cur_dirty_region) - 1;
-      _dirty_region_buffer[allocated] = region;
+    G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+    WorkGang* workers = g1h->workers();
+    uint const max_workers = workers->active_workers();
+
+    uint const start_pos = num_regions * worker_id / max_workers;
+    uint cur = start_pos;
+
+    do {
+      bool result = cl->do_heap_region(g1h->region_at(_next_dirty_regions->at(cur)));
+      guarantee(!result, "Not allowed to ask for early termination.");
+      cur++;
+      if (cur == _next_dirty_regions->size()) {
+        cur = 0;
+      }
+    } while (cur != start_pos);
+  }
+
+  // Attempt to claim the given region in the collection set for iteration. Returns true
+  // if this call caused the transition from Unclaimed to Claimed.
+  inline bool claim_collection_set_region(uint region) {
+    assert(region < _max_regions, "Tried to access invalid region %u", region);
+    if (_collection_set_iter_state[region]) {
+      return false;
     }
+    return !Atomic::cmpxchg(true, &_collection_set_iter_state[region], false);
+  }
+
+  bool has_cards_to_scan(uint region) {
+    assert(region < _max_regions, "Tried to access invalid region %u", region);
+    return _card_table_scan_state[region] < HeapRegion::CardsPerRegion;
+  }
+
+  uint claim_cards_to_scan(uint region, uint increment) {
+    assert(region < _max_regions, "Tried to access invalid region %u", region);
+    return Atomic::add(increment, &_card_table_scan_state[region]) - increment;
+  }
+
+  void add_dirty_region(uint const region) {
+#ifdef ASSERT
+   HeapRegion* hr = G1CollectedHeap::heap()->region_at(region);
+   assert(!hr->in_collection_set() && hr->is_old_or_humongous_or_archive(),
+          "Region %u is not suitable for scanning, is %sin collection set or %s",
+          hr->hrm_index(), hr->in_collection_set() ? "" : "not ", hr->get_short_type_str());
+#endif
+    _next_dirty_regions->add_dirty_region(region);
+  }
+
+  void add_all_dirty_region(uint region) {
+#ifdef ASSERT
+    HeapRegion* hr = G1CollectedHeap::heap()->region_at(region);
+    assert(hr->in_collection_set(),
+           "Only add young regions to all dirty regions directly but %u is %s",
+           hr->hrm_index(), hr->get_short_type_str());
+#endif
+    _all_dirty_regions->add_dirty_region(region);
+  }
+
+  void set_scan_top(uint region_idx, HeapWord* value) {
+    _scan_top[region_idx] = value;
   }
 
   HeapWord* scan_top(uint region_idx) const {
@@ -254,30 +731,7 @@
   }
 
   void clear_scan_top(uint region_idx) {
-    _scan_top[region_idx] = NULL;
-  }
-
-  // Clear the card table of "dirty" regions.
-  void clear_card_table(WorkGang* workers) {
-    if (_cur_dirty_region == 0) {
-      return;
-    }
-
-    size_t const num_chunks = align_up(_cur_dirty_region * HeapRegion::CardsPerRegion, G1ClearCardTableTask::chunk_size()) / G1ClearCardTableTask::chunk_size();
-    uint const num_workers = (uint)MIN2(num_chunks, (size_t)workers->active_workers());
-    size_t const chunk_length = G1ClearCardTableTask::chunk_size() / HeapRegion::CardsPerRegion;
-
-    // Iterate over the dirty cards region list.
-    G1ClearCardTableTask cl(G1CollectedHeap::heap(), _dirty_region_buffer, _cur_dirty_region, chunk_length);
-
-    log_debug(gc, ergo)("Running %s using %u workers for " SIZE_FORMAT " "
-                        "units of work for " SIZE_FORMAT " regions.",
-                        cl.name(), num_workers, num_chunks, _cur_dirty_region);
-    workers->run_task(&cl, num_workers);
-
-#ifndef PRODUCT
-    G1CollectedHeap::heap()->verifier()->verify_card_table_cleanup();
-#endif
+    set_scan_top(region_idx, NULL);
   }
 };
 
@@ -294,9 +748,7 @@
 }
 
 G1RemSet::~G1RemSet() {
-  if (_scan_state != NULL) {
-    delete _scan_state;
-  }
+  delete _scan_state;
 }
 
 uint G1RemSet::num_par_rem_sets() {
@@ -308,181 +760,252 @@
   _scan_state->initialize(max_regions);
 }
 
-class G1ScanRSForRegionClosure : public HeapRegionClosure {
+// Helper class to scan and detect ranges of cards that need to be scanned on the
+// card table.
+class G1CardTableScanner : public StackObj {
+public:
+  typedef CardTable::CardValue CardValue;
+
+private:
+  CardValue* const _base_addr;
+
+  CardValue* _cur_addr;
+  CardValue* const _end_addr;
+
+  static const size_t ToScanMask = G1CardTable::g1_card_already_scanned;
+  static const size_t ExpandedToScanMask = G1CardTable::WordAlreadyScanned;
+
+  bool cur_addr_aligned() const {
+    return ((uintptr_t)_cur_addr) % sizeof(size_t) == 0;
+  }
+
+  bool cur_card_is_dirty() const {
+    CardValue value = *_cur_addr;
+    return (value & ToScanMask) == 0;
+  }
+
+  bool cur_word_of_cards_contains_any_dirty_card() const {
+    assert(cur_addr_aligned(), "Current address should be aligned");
+    size_t const value = *(size_t*)_cur_addr;
+    return (~value & ExpandedToScanMask) != 0;
+  }
+
+  bool cur_word_of_cards_all_dirty_cards() const {
+    size_t const value = *(size_t*)_cur_addr;
+    return value == G1CardTable::WordAllDirty;
+  }
+
+  size_t get_and_advance_pos() {
+    _cur_addr++;
+    return pointer_delta(_cur_addr, _base_addr, sizeof(CardValue)) - 1;
+  }
+
+public:
+  G1CardTableScanner(CardValue* start_card, size_t size) :
+    _base_addr(start_card),
+    _cur_addr(start_card),
+    _end_addr(start_card + size) {
+
+    assert(is_aligned(start_card, sizeof(size_t)), "Unaligned start addr " PTR_FORMAT, p2i(start_card));
+    assert(is_aligned(size, sizeof(size_t)), "Unaligned size " SIZE_FORMAT, size);
+  }
+
+  size_t find_next_dirty() {
+    while (!cur_addr_aligned()) {
+      if (cur_card_is_dirty()) {
+        return get_and_advance_pos();
+      }
+      _cur_addr++;
+    }
+
+    assert(cur_addr_aligned(), "Current address should be aligned now.");
+    while (_cur_addr != _end_addr) {
+      if (cur_word_of_cards_contains_any_dirty_card()) {
+        for (size_t i = 0; i < sizeof(size_t); i++) {
+          if (cur_card_is_dirty()) {
+            return get_and_advance_pos();
+          }
+          _cur_addr++;
+        }
+        assert(false, "Should not reach here given we detected a dirty card in the word.");
+      }
+      _cur_addr += sizeof(size_t);
+    }
+    return get_and_advance_pos();
+  }
+
+  size_t find_next_non_dirty() {
+    assert(_cur_addr <= _end_addr, "Not allowed to search for marks after area.");
+
+    while (!cur_addr_aligned()) {
+      if (!cur_card_is_dirty()) {
+        return get_and_advance_pos();
+      }
+      _cur_addr++;
+    }
+
+    assert(cur_addr_aligned(), "Current address should be aligned now.");
+    while (_cur_addr != _end_addr) {
+      if (!cur_word_of_cards_all_dirty_cards()) {
+        for (size_t i = 0; i < sizeof(size_t); i++) {
+          if (!cur_card_is_dirty()) {
+            return get_and_advance_pos();
+          }
+          _cur_addr++;
+        }
+        assert(false, "Should not reach here given we detected a non-dirty card in the word.");
+      }
+      _cur_addr += sizeof(size_t);
+    }
+    return get_and_advance_pos();
+  }
+};
+
+// Helper class to claim dirty chunks within the card table.
+class G1CardTableChunkClaimer {
+  G1RemSetScanState* _scan_state;
+  uint _region_idx;
+  uint _cur_claim;
+
+public:
+  G1CardTableChunkClaimer(G1RemSetScanState* scan_state, uint region_idx) :
+    _scan_state(scan_state),
+    _region_idx(region_idx),
+    _cur_claim(0) {
+    guarantee(size() <= HeapRegion::CardsPerRegion, "Should not claim more space than possible.");
+  }
+
+  bool has_next() {
+    while (true) {
+      _cur_claim = _scan_state->claim_cards_to_scan(_region_idx, size());
+      if (_cur_claim >= HeapRegion::CardsPerRegion) {
+        return false;
+      }
+      if (_scan_state->chunk_needs_scan(_region_idx, _cur_claim)) {
+        return true;
+      }
+    }
+  }
+
+  uint value() const { return _cur_claim; }
+  uint size() const { return _scan_state->scan_chunk_size(); }
+};
+
+// Scans a heap region for dirty cards.
+class G1ScanHRForRegionClosure : public HeapRegionClosure {
   G1CollectedHeap* _g1h;
-  G1CardTable *_ct;
+  G1CardTable* _ct;
+  G1BlockOffsetTable* _bot;
 
   G1ParScanThreadState* _pss;
-  G1ScanCardClosure* _scan_objs_on_card_cl;
 
   G1RemSetScanState* _scan_state;
 
   G1GCPhaseTimes::GCParPhases _phase;
 
-  uint   _worker_i;
-
-  size_t _opt_refs_scanned;
-  size_t _opt_refs_memory_used;
+  uint   _worker_id;
 
   size_t _cards_scanned;
-  size_t _cards_claimed;
-  size_t _cards_skipped;
+  size_t _blocks_scanned;
+  size_t _chunks_claimed;
 
   Tickspan _rem_set_root_scan_time;
   Tickspan _rem_set_trim_partially_time;
 
-  Tickspan _strong_code_root_scan_time;
-  Tickspan _strong_code_trim_partially_time;
-
-  void claim_card(size_t card_index, const uint region_idx_for_card) {
-    _ct->set_card_claimed(card_index);
-    _scan_state->add_dirty_region(region_idx_for_card);
-  }
-
-  void scan_card(MemRegion mr, uint region_idx_for_card) {
+  void scan_memregion(uint region_idx_for_card, MemRegion mr) {
     HeapRegion* const card_region = _g1h->region_at(region_idx_for_card);
-    assert(!card_region->is_young(), "Should not scan card in young region %u", region_idx_for_card);
-    card_region->oops_on_card_seq_iterate_careful<true>(mr, _scan_objs_on_card_cl);
-    _scan_objs_on_card_cl->trim_queue_partially();
-    _cards_scanned++;
+    G1ScanCardClosure card_cl(_g1h, _pss);
+    card_region->oops_on_card_seq_iterate_careful<true>(mr, &card_cl);
+    _pss->trim_queue_partially();
   }
 
-  void scan_opt_rem_set_roots(HeapRegion* r) {
-    EventGCPhaseParallel event;
-
-    G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
-
-    G1ScanCardClosure scan_cl(_g1h, _pss);
-    G1ScanRSForOptionalClosure cl(_g1h, &scan_cl);
-    _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops());
-    _opt_refs_memory_used += opt_rem_set_list->used_memory();
-
-    event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
-  }
-
-  void scan_rem_set_roots(HeapRegion* r) {
-    EventGCPhaseParallel event;
-    uint const region_idx = r->hrm_index();
-
-    if (_scan_state->claim_iter(region_idx)) {
-      // If we ever free the collection set concurrently, we should also
-      // clear the card table concurrently therefore we won't need to
-      // add regions of the collection set to the dirty cards region.
-      _scan_state->add_dirty_region(region_idx);
-    }
-
-    if (r->rem_set()->cardset_is_empty()) {
+  void do_claimed_block(uint const region_idx_for_card, size_t const first_card, size_t const num_cards) {
+    HeapWord* const card_start = _bot->address_for_index_raw(first_card);
+#ifdef ASSERT
+    HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card);
+    assert(hr == NULL || hr->is_in_reserved(card_start),
+             "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
+#endif
+    HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
+    if (card_start >= top) {
       return;
     }
 
-    // We claim cards in blocks so as to reduce the contention.
-    size_t const block_size = G1RSetScanBlockSize;
-
-    HeapRegionRemSetIterator iter(r->rem_set());
-    size_t card_index;
-
-    size_t claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
-    for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
-      if (current_card >= claimed_card_block + block_size) {
-        claimed_card_block = _scan_state->iter_claimed_next(region_idx, block_size);
-      }
-      if (current_card < claimed_card_block) {
-        _cards_skipped++;
-        continue;
-      }
-      _cards_claimed++;
-
-      HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index);
-      uint const region_idx_for_card = _g1h->addr_to_region(card_start);
+    MemRegion mr(card_start, MIN2(card_start + ((size_t)num_cards << BOTConstants::LogN_words), top));
+    scan_memregion(region_idx_for_card, mr);
 
-#ifdef ASSERT
-      HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card);
-      assert(hr == NULL || hr->is_in_reserved(card_start),
-             "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index());
-#endif
-      HeapWord* const top = _scan_state->scan_top(region_idx_for_card);
-      if (card_start >= top) {
-        continue;
-      }
+    _cards_scanned += num_cards;
+  }
 
-      // If the card is dirty, then G1 will scan it during Update RS.
-      if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) {
-        continue;
-      }
-
-      // We claim lazily (so races are possible but they're benign), which reduces the
-      // number of duplicate scans (the rsets of the regions in the cset can intersect).
-      // Claim the card after checking bounds above: the remembered set may contain
-      // random cards into current survivor, and we would then have an incorrectly
-      // claimed card in survivor space. Card table clear does not reset the card table
-      // of survivor space regions.
-      claim_card(card_index, region_idx_for_card);
-
-      MemRegion const mr(card_start, MIN2(card_start + BOTConstants::N_words, top));
-
-      scan_card(mr, region_idx_for_card);
-    }
-    event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase));
+  ALWAYSINLINE void do_card_block(uint const region_idx, size_t const first_card, size_t const num_cards) {
+    _ct->mark_as_scanned(first_card, num_cards);
+    do_claimed_block(region_idx, first_card, num_cards);
+    _blocks_scanned++;
   }
 
-  void scan_strong_code_roots(HeapRegion* r) {
+   void scan_heap_roots(HeapRegion* r) {
     EventGCPhaseParallel event;
-    // We pass a weak code blobs closure to the remembered set scanning because we want to avoid
-    // treating the nmethods visited to act as roots for concurrent marking.
-    // We only want to make sure that the oops in the nmethods are adjusted with regard to the
-    // objects copied by the current evacuation.
-    r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
-    event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots));
+    uint const region_idx = r->hrm_index();
+
+    ResourceMark rm;
+
+    G1CardTableChunkClaimer claim(_scan_state, region_idx);
+
+    while (claim.has_next()) {
+      size_t const region_card_base_idx = ((size_t)region_idx << HeapRegion::LogCardsPerRegion) + claim.value();
+      CardTable::CardValue* const base_addr = _ct->byte_for_index(region_card_base_idx);
+
+      G1CardTableScanner scan(base_addr, claim.size());
+
+      size_t first_scan_idx = scan.find_next_dirty();
+      while (first_scan_idx != claim.size()) {
+        assert(*_ct->byte_for_index(region_card_base_idx + first_scan_idx) <= 0x1, "is %d at region %u idx " SIZE_FORMAT, *_ct->byte_for_index(region_card_base_idx + first_scan_idx), region_idx, first_scan_idx);
+
+        size_t const last_scan_idx = scan.find_next_non_dirty();
+        size_t const len = last_scan_idx - first_scan_idx;
+
+        do_card_block(region_idx, region_card_base_idx + first_scan_idx, len);
+
+        if (last_scan_idx == claim.size()) {
+          break;
+        }
+
+        first_scan_idx = scan.find_next_dirty();
+      }
+      _chunks_claimed++;
+    }
+
+    event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ScanHR));
   }
 
 public:
-  G1ScanRSForRegionClosure(G1RemSetScanState* scan_state,
-                           G1ScanCardClosure* scan_obj_on_card,
+  G1ScanHRForRegionClosure(G1RemSetScanState* scan_state,
                            G1ParScanThreadState* pss,
-                           G1GCPhaseTimes::GCParPhases phase,
-                           uint worker_i) :
+                           uint worker_id,
+                           G1GCPhaseTimes::GCParPhases phase) :
     _g1h(G1CollectedHeap::heap()),
     _ct(_g1h->card_table()),
+    _bot(_g1h->bot()),
     _pss(pss),
-    _scan_objs_on_card_cl(scan_obj_on_card),
     _scan_state(scan_state),
     _phase(phase),
-    _worker_i(worker_i),
-    _opt_refs_scanned(0),
-    _opt_refs_memory_used(0),
+    _worker_id(worker_id),
     _cards_scanned(0),
-    _cards_claimed(0),
-    _cards_skipped(0),
+    _blocks_scanned(0),
+    _chunks_claimed(0),
     _rem_set_root_scan_time(),
-    _rem_set_trim_partially_time(),
-    _strong_code_root_scan_time(),
-    _strong_code_trim_partially_time() { }
+    _rem_set_trim_partially_time() {
+  }
 
   bool do_heap_region(HeapRegion* r) {
-    assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index());
+    assert(!r->in_collection_set() && r->is_old_or_humongous_or_archive(),
+           "Should only be called on old gen non-collection set regions but region %u is not.",
+           r->hrm_index());
     uint const region_idx = r->hrm_index();
 
-    // The individual references for the optional remembered set are per-worker, so we
-    // always need to scan them.
-    if (r->has_index_in_opt_cset()) {
+    if (_scan_state->has_cards_to_scan(region_idx)) {
       G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
-      scan_opt_rem_set_roots(r);
-    }
-
-    // Do an early out if we know we are complete.
-    if (_scan_state->iter_is_complete(region_idx)) {
-      return false;
-    }
-
-    {
-      G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time);
-      scan_rem_set_roots(r);
-    }
-
-    if (_scan_state->set_iter_complete(region_idx)) {
-      G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time);
-      // Scan the strong code root list attached to the current region
-      scan_strong_code_roots(r);
+      scan_heap_roots(r);
     }
     return false;
   }
@@ -490,120 +1013,156 @@
   Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; }
   Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; }
 
+  size_t cards_scanned() const { return _cards_scanned; }
+  size_t blocks_scanned() const { return _blocks_scanned; }
+  size_t chunks_claimed() const { return _chunks_claimed; }
+};
+
+void G1RemSet::scan_heap_roots(G1ParScanThreadState* pss,
+                            uint worker_id,
+                            G1GCPhaseTimes::GCParPhases scan_phase,
+                            G1GCPhaseTimes::GCParPhases objcopy_phase) {
+  G1ScanHRForRegionClosure cl(_scan_state, pss, worker_id, scan_phase);
+  _scan_state->iterate_dirty_regions_from(&cl, worker_id);
+
+  G1GCPhaseTimes* p = _g1p->phase_times();
+
+  p->record_or_add_time_secs(objcopy_phase, worker_id, cl.rem_set_trim_partially_time().seconds());
+
+  p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_root_scan_time().seconds());
+  p->record_or_add_thread_work_item(scan_phase, worker_id, cl.cards_scanned(), G1GCPhaseTimes::ScanHRScannedCards);
+  p->record_or_add_thread_work_item(scan_phase, worker_id, cl.blocks_scanned(), G1GCPhaseTimes::ScanHRScannedBlocks);
+  p->record_or_add_thread_work_item(scan_phase, worker_id, cl.chunks_claimed(), G1GCPhaseTimes::ScanHRClaimedChunks);
+}
+
+// Heap region closure to be applied to all regions in the current collection set
+// increment to fix up non-card related roots.
+class G1ScanCollectionSetRegionClosure : public HeapRegionClosure {
+  G1ParScanThreadState* _pss;
+  G1RemSetScanState* _scan_state;
+
+  G1GCPhaseTimes::GCParPhases _scan_phase;
+  G1GCPhaseTimes::GCParPhases _code_roots_phase;
+
+  uint _worker_id;
+
+  size_t _opt_refs_scanned;
+  size_t _opt_refs_memory_used;
+
+  Tickspan _strong_code_root_scan_time;
+  Tickspan _strong_code_trim_partially_time;
+
+  Tickspan _rem_set_opt_root_scan_time;
+  Tickspan _rem_set_opt_trim_partially_time;
+
+  void scan_opt_rem_set_roots(HeapRegion* r) {
+    EventGCPhaseParallel event;
+
+    G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r);
+
+    G1ScanCardClosure scan_cl(G1CollectedHeap::heap(), _pss);
+    G1ScanRSForOptionalClosure cl(G1CollectedHeap::heap(), &scan_cl);
+    _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops());
+    _opt_refs_memory_used += opt_rem_set_list->used_memory();
+
+    event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_scan_phase));
+  }
+
+public:
+  G1ScanCollectionSetRegionClosure(G1RemSetScanState* scan_state,
+                                   G1ParScanThreadState* pss,
+                                   uint worker_i,
+                                   G1GCPhaseTimes::GCParPhases scan_phase,
+                                   G1GCPhaseTimes::GCParPhases code_roots_phase) :
+    _pss(pss),
+    _scan_state(scan_state),
+    _scan_phase(scan_phase),
+    _code_roots_phase(code_roots_phase),
+    _worker_id(worker_i),
+    _opt_refs_scanned(0),
+    _opt_refs_memory_used(0),
+    _strong_code_root_scan_time(),
+    _strong_code_trim_partially_time(),
+    _rem_set_opt_root_scan_time(),
+    _rem_set_opt_trim_partially_time() { }
+
+  bool do_heap_region(HeapRegion* r) {
+    uint const region_idx = r->hrm_index();
+
+    // The individual references for the optional remembered set are per-worker, so we
+    // always need to scan them.
+    if (r->has_index_in_opt_cset()) {
+      G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_opt_root_scan_time, _rem_set_opt_trim_partially_time);
+      scan_opt_rem_set_roots(r);
+    }
+
+    if (_scan_state->claim_collection_set_region(region_idx)) {
+      EventGCPhaseParallel event;
+
+      G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time);
+      // Scan the strong code root list attached to the current region
+      r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
+
+      event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_code_roots_phase));
+    }
+
+    return false;
+  }
+
   Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time;  }
   Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; }
 
-  size_t cards_scanned() const { return _cards_scanned; }
-  size_t cards_claimed() const { return _cards_claimed; }
-  size_t cards_skipped() const { return _cards_skipped; }
+  Tickspan rem_set_opt_root_scan_time() const { return _rem_set_opt_root_scan_time; }
+  Tickspan rem_set_opt_trim_partially_time() const { return _rem_set_opt_trim_partially_time; }
 
   size_t opt_refs_scanned() const { return _opt_refs_scanned; }
   size_t opt_refs_memory_used() const { return _opt_refs_memory_used; }
 };
 
-void G1RemSet::scan_rem_set(G1ParScanThreadState* pss,
-                            uint worker_i,
-                            G1GCPhaseTimes::GCParPhases scan_phase,
-                            G1GCPhaseTimes::GCParPhases objcopy_phase,
-                            G1GCPhaseTimes::GCParPhases coderoots_phase) {
-  assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering.");
-
-  G1ScanCardClosure scan_cl(_g1h, pss);
-  G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i);
-  _g1h->collection_set_iterate_increment_from(&cl, worker_i);
-
-  G1GCPhaseTimes* p = _g1p->phase_times();
-
-  p->record_or_add_time_secs(objcopy_phase, worker_i, cl.rem_set_trim_partially_time().seconds());
+void G1RemSet::scan_collection_set_regions(G1ParScanThreadState* pss,
+                                           uint worker_id,
+                                           G1GCPhaseTimes::GCParPhases scan_phase,
+                                           G1GCPhaseTimes::GCParPhases coderoots_phase,
+                                           G1GCPhaseTimes::GCParPhases objcopy_phase) {
+  G1ScanCollectionSetRegionClosure cl(_scan_state, pss, worker_id, scan_phase, coderoots_phase);
+  _g1h->collection_set_iterate_increment_from(&cl, worker_id);
 
-  p->record_or_add_time_secs(scan_phase, worker_i, cl.rem_set_root_scan_time().seconds());
-  p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards);
-  p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards);
-  p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards);
-  // At this time we only record some metrics for the optional remembered set.
-  if (scan_phase == G1GCPhaseTimes::OptScanRS) {
-    p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanRSScannedOptRefs);
-    p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanRSUsedMemory);
-  }
-
-  p->record_or_add_time_secs(coderoots_phase, worker_i, cl.strong_code_root_scan_time().seconds());
-  p->add_time_secs(objcopy_phase, worker_i, cl.strong_code_root_trim_partially_time().seconds());
-}
-
-// Closure used for updating rem sets. Only called during an evacuation pause.
-class G1RefineCardClosure: public G1CardTableEntryClosure {
-  G1RemSet* _g1rs;
-  G1ScanCardClosure* _update_rs_cl;
-
-  size_t _cards_scanned;
-  size_t _cards_skipped;
-public:
-  G1RefineCardClosure(G1CollectedHeap* g1h, G1ScanCardClosure* update_rs_cl) :
-    _g1rs(g1h->rem_set()), _update_rs_cl(update_rs_cl), _cards_scanned(0), _cards_skipped(0)
-  {}
+  G1GCPhaseTimes* p = _g1h->phase_times();
 
-  bool do_card_ptr(CardValue* card_ptr, uint worker_i) {
-    // The only time we care about recording cards that
-    // contain references that point into the collection set
-    // is during RSet updating within an evacuation pause.
-    // In this case worker_i should be the id of a GC worker thread.
-    assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
-
-    bool card_scanned = _g1rs->refine_card_during_gc(card_ptr, _update_rs_cl);
-
-    if (card_scanned) {
-      _update_rs_cl->trim_queue_partially();
-      _cards_scanned++;
-    } else {
-      _cards_skipped++;
-    }
-    return true;
-  }
-
-  size_t cards_scanned() const { return _cards_scanned; }
-  size_t cards_skipped() const { return _cards_skipped; }
-};
+  p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_root_scan_time().seconds());
+  p->record_or_add_time_secs(scan_phase, worker_id, cl.rem_set_opt_trim_partially_time().seconds());
 
-void G1RemSet::update_rem_set(G1ParScanThreadState* pss, uint worker_i) {
-  G1GCPhaseTimes* p = _g1p->phase_times();
-
-  // Apply closure to log entries in the HCC.
-  if (G1HotCardCache::default_use_cache()) {
-    G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i);
+  p->record_or_add_time_secs(coderoots_phase, worker_id, cl.strong_code_root_scan_time().seconds());
+  p->add_time_secs(objcopy_phase, worker_id, cl.strong_code_root_trim_partially_time().seconds());
 
-    G1ScanCardClosure scan_hcc_cl(_g1h, pss);
-    G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl);
-    _g1h->iterate_hcc_closure(&refine_card_cl, worker_i);
-  }
-
-  // Now apply the closure to all remaining log entries.
-  {
-    G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i);
-
-    G1ScanCardClosure update_rs_cl(_g1h, pss);
-    G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl);
-    _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i);
-
-    p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards);
-    p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards);
+  // At this time we record some metrics only for the evacuations after the initial one.
+  if (scan_phase == G1GCPhaseTimes::OptScanHR) {
+    p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanHRScannedOptRefs);
+    p->record_or_add_thread_work_item(scan_phase, worker_id, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanHRUsedMemory);
   }
 }
 
-void G1RemSet::prepare_for_scan_rem_set() {
-  G1BarrierSet::dirty_card_queue_set().concatenate_logs();
-  _scan_state->reset();
+void G1RemSet::prepare_for_scan_heap_roots() {
+  G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
+  dcqs.concatenate_logs();
+
+  _scan_state->prepare();
 }
 
-void G1RemSet::prepare_for_scan_rem_set(uint region_idx) {
+void G1RemSet::merge_heap_roots(bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase) {
+  _scan_state->merge_heap_roots(_g1h->workers(), remembered_set_only, merge_phase);
+}
+
+void G1RemSet::prepare_for_scan_heap_roots(uint region_idx) {
   _scan_state->clear_scan_top(region_idx);
 }
 
-void G1RemSet::cleanup_after_scan_rem_set() {
+void G1RemSet::cleanup_after_scan_heap_roots() {
   G1GCPhaseTimes* phase_times = _g1h->phase_times();
 
   // Set all cards back to clean.
   double start = os::elapsedTime();
-  _scan_state->clear_card_table(_g1h->workers());
+  _scan_state->cleanup(_g1h->workers());
   phase_times->record_clear_ct_time((os::elapsedTime() - start) * 1000.0);
 }
 
@@ -759,53 +1318,6 @@
   G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr);
 }
 
-bool G1RemSet::refine_card_during_gc(CardValue* card_ptr,
-                                     G1ScanCardClosure* update_rs_cl) {
-  assert(_g1h->is_gc_active(), "Only call during GC");
-
-  // Construct the region representing the card.
-  HeapWord* card_start = _ct->addr_for(card_ptr);
-  // And find the region containing it.
-  uint const card_region_idx = _g1h->addr_to_region(card_start);
-
-  HeapWord* scan_limit = _scan_state->scan_top(card_region_idx);
-  if (scan_limit == NULL) {
-    // This is a card into an uncommitted region. We need to bail out early as we
-    // should not access the corresponding card table entry.
-    return false;
-  }
-
-  check_card_ptr(card_ptr, _ct);
-
-  // If the card is no longer dirty, nothing to do. This covers cards that were already
-  // scanned as parts of the remembered sets.
-  if (*card_ptr != G1CardTable::dirty_card_val()) {
-    return false;
-  }
-
-  // We claim lazily (so races are possible but they're benign), which reduces the
-  // number of potential duplicate scans (multiple threads may enqueue the same card twice).
-  *card_ptr = G1CardTable::clean_card_val() | G1CardTable::claimed_card_val();
-
-  _scan_state->add_dirty_region(card_region_idx);
-  if (scan_limit <= card_start) {
-    // If the card starts above the area in the region containing objects to scan, skip it.
-    return false;
-  }
-
-  // Don't use addr_for(card_ptr + 1) which can ask for
-  // a card beyond the heap.
-  HeapWord* card_end = card_start + G1CardTable::card_size_in_words;
-  MemRegion dirty_region(card_start, MIN2(scan_limit, card_end));
-  assert(!dirty_region.is_empty(), "sanity");
-
-  HeapRegion* const card_region = _g1h->region_at(card_region_idx);
-  assert(!card_region->is_young(), "Should not scan card in young region %u", card_region_idx);
-  bool card_processed = card_region->oops_on_card_seq_iterate_careful<true>(dirty_region, update_rs_cl);
-  assert(card_processed, "must be");
-  return true;
-}
-
 void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) {
   if ((G1SummarizeRSetStatsPeriod > 0) && log_is_enabled(Trace, gc, remset) &&
       (period_count % G1SummarizeRSetStatsPeriod == 0)) {
--- a/src/hotspot/share/gc/g1/g1RemSet.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -46,6 +46,7 @@
 class G1HotCardCache;
 class G1RemSetScanState;
 class G1ParScanThreadState;
+class G1ParScanThreadStateSet;
 class G1Policy;
 class G1ScanCardClosure;
 class HeapRegionClaimer;
@@ -84,39 +85,39 @@
            G1HotCardCache* hot_card_cache);
   ~G1RemSet();
 
-  // Scan all remembered sets of the collection set for references into the collection
-  // set.
-  // Further applies heap_region_codeblobs on the oops of the unmarked nmethods on the strong code
-  // roots list for each region in the collection set.
-  void scan_rem_set(G1ParScanThreadState* pss,
-                    uint worker_i,
-                    G1GCPhaseTimes::GCParPhases scan_phase,
-                    G1GCPhaseTimes::GCParPhases objcopy_phase,
-                    G1GCPhaseTimes::GCParPhases coderoots_phase);
+  // Scan all cards in the non-collection set regions that potentially contain
+  // references into the current whole collection set.
+  void scan_heap_roots(G1ParScanThreadState* pss,
+                       uint worker_id,
+                       G1GCPhaseTimes::GCParPhases scan_phase,
+                       G1GCPhaseTimes::GCParPhases objcopy_phase);
+
+  // Merge cards from various sources (remembered sets, hot card cache, log buffers)
+  // and calculate the cards that need to be scanned later (via scan_heap_roots()).
+  // If remembered_set_only is set, only merge remembered set cards.
+  void merge_heap_roots(bool remembered_set_only, G1GCPhaseTimes::GCParPhases merge_phase);
 
-  // Flush remaining refinement buffers for cross-region references to either evacuate references
-  // into the collection set or update the remembered set.
-  void update_rem_set(G1ParScanThreadState* pss, uint worker_i);
-
-  // Prepare for and cleanup after scanning the remembered sets. Must be called
+  // Prepare for and cleanup after scanning the heap roots. Must be called
   // once before and after in sequential code.
-  void prepare_for_scan_rem_set();
-  void cleanup_after_scan_rem_set();
-  // Prepares the given region for remembered set scanning.
-  void prepare_for_scan_rem_set(uint region_idx);
+  void prepare_for_scan_heap_roots();
+  // Cleans the card table from temporary duplicate detection information.
+  void cleanup_after_scan_heap_roots();
+  // Prepares the given region for heap root scanning.
+  void prepare_for_scan_heap_roots(uint region_idx);
 
-  G1RemSetScanState* scan_state() const { return _scan_state; }
+  // Do work for regions in the current increment of the collection set, scanning
+  // non-card based (heap) roots.
+  void scan_collection_set_regions(G1ParScanThreadState* pss,
+                                   uint worker_id,
+                                   G1GCPhaseTimes::GCParPhases scan_phase,
+                                   G1GCPhaseTimes::GCParPhases coderoots_phase,
+                                   G1GCPhaseTimes::GCParPhases objcopy_phase);
 
   // Refine the card corresponding to "card_ptr". Safe to be called concurrently
   // to the mutator.
   void refine_card_concurrently(CardValue* card_ptr,
                                 uint worker_i);
 
-  // Refine the card corresponding to "card_ptr", applying the given closure to
-  // all references found. Must only be called during gc.
-  // Returns whether the card has been scanned.
-  bool refine_card_during_gc(CardValue* card_ptr, G1ScanCardClosure* update_rs_cl);
-
   // Print accumulated summary info from the start of the VM.
   void print_summary_info();
 
--- a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -35,12 +35,10 @@
 G1SATBMarkQueueSet::G1SATBMarkQueueSet() : _g1h(NULL) {}
 
 void G1SATBMarkQueueSet::initialize(G1CollectedHeap* g1h,
-                                    Monitor* cbl_mon,
                                     BufferNode::Allocator* allocator,
                                     size_t process_completed_buffers_threshold,
                                     uint buffer_enqueue_threshold_percentage) {
-  SATBMarkQueueSet::initialize(cbl_mon,
-                               allocator,
+  SATBMarkQueueSet::initialize(allocator,
                                process_completed_buffers_threshold,
                                buffer_enqueue_threshold_percentage);
   _g1h = g1h;
--- a/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1SATBMarkQueueSet.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,6 @@
   G1SATBMarkQueueSet();
 
   void initialize(G1CollectedHeap* g1h,
-                  Monitor* cbl_mon,
                   BufferNode::Allocator* allocator,
                   size_t process_completed_buffers_threshold,
                   uint buffer_enqueue_threshold_percentage);
--- a/src/hotspot/share/gc/g1/heapRegion.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/heapRegion.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -49,6 +49,7 @@
 
 int    HeapRegion::LogOfHRGrainBytes = 0;
 int    HeapRegion::LogOfHRGrainWords = 0;
+int    HeapRegion::LogCardsPerRegion = 0;
 size_t HeapRegion::GrainBytes        = 0;
 size_t HeapRegion::GrainWords        = 0;
 size_t HeapRegion::CardsPerRegion    = 0;
@@ -105,6 +106,8 @@
   guarantee(CardsPerRegion == 0, "we should only set it once");
   CardsPerRegion = GrainBytes >> G1CardTable::card_shift;
 
+  LogCardsPerRegion = log2_long((jlong) CardsPerRegion);
+
   if (G1HeapRegionSize != GrainBytes) {
     FLAG_SET_ERGO(G1HeapRegionSize, GrainBytes);
   }
--- a/src/hotspot/share/gc/g1/heapRegion.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/heapRegion.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -60,7 +60,6 @@
 class G1CMBitMap;
 class G1IsAliveAndApplyClosure;
 class HeapRegionRemSet;
-class HeapRegionRemSetIterator;
 class HeapRegion;
 class HeapRegionSetBase;
 class nmethod;
@@ -315,6 +314,7 @@
 
   static int    LogOfHRGrainBytes;
   static int    LogOfHRGrainWords;
+  static int    LogCardsPerRegion;
 
   static size_t GrainBytes;
   static size_t GrainWords;
--- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -27,7 +27,7 @@
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1ConcurrentRefine.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
-#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/heapRegionRemSet.inline.hpp"
 #include "gc/shared/space.inline.hpp"
 #include "memory/allocation.hpp"
 #include "memory/padded.inline.hpp"
@@ -42,195 +42,21 @@
 const char* HeapRegionRemSet::_state_strings[] =  {"Untracked", "Updating", "Complete"};
 const char* HeapRegionRemSet::_short_state_strings[] =  {"UNTRA", "UPDAT", "CMPLT"};
 
-class PerRegionTable: public CHeapObj<mtGC> {
-  friend class OtherRegionsTable;
-  friend class HeapRegionRemSetIterator;
-
-  HeapRegion*     _hr;
-  CHeapBitMap     _bm;
-  jint            _occupied;
-
-  // next pointer for free/allocated 'all' list
-  PerRegionTable* _next;
-
-  // prev pointer for the allocated 'all' list
-  PerRegionTable* _prev;
-
-  // next pointer in collision list
-  PerRegionTable * _collision_list_next;
-
-  // Global free list of PRTs
-  static PerRegionTable* volatile _free_list;
-
-protected:
-  // We need access in order to union things into the base table.
-  BitMap* bm() { return &_bm; }
-
-  PerRegionTable(HeapRegion* hr) :
-    _hr(hr),
-    _bm(HeapRegion::CardsPerRegion, mtGC),
-    _occupied(0),
-    _next(NULL), _prev(NULL),
-    _collision_list_next(NULL)
-  {}
-
-  void add_card_work(CardIdx_t from_card, bool par) {
-    if (!_bm.at(from_card)) {
-      if (par) {
-        if (_bm.par_at_put(from_card, 1)) {
-          Atomic::inc(&_occupied);
-        }
-      } else {
-        _bm.at_put(from_card, 1);
-        _occupied++;
-      }
-    }
-  }
-
-  void add_reference_work(OopOrNarrowOopStar from, bool par) {
-    // Must make this robust in case "from" is not in "_hr", because of
-    // concurrency.
-
-    HeapRegion* loc_hr = hr();
-    // If the test below fails, then this table was reused concurrently
-    // with this operation.  This is OK, since the old table was coarsened,
-    // and adding a bit to the new table is never incorrect.
-    if (loc_hr->is_in_reserved(from)) {
-      CardIdx_t from_card = OtherRegionsTable::card_within_region(from, loc_hr);
-      add_card_work(from_card, par);
+PerRegionTable* PerRegionTable::alloc(HeapRegion* hr) {
+  PerRegionTable* fl = _free_list;
+  while (fl != NULL) {
+    PerRegionTable* nxt = fl->next();
+    PerRegionTable* res = Atomic::cmpxchg(nxt, &_free_list, fl);
+    if (res == fl) {
+      fl->init(hr, true);
+      return fl;
+    } else {
+      fl = _free_list;
     }
   }
-
-public:
-
-  HeapRegion* hr() const { return OrderAccess::load_acquire(&_hr); }
-
-  jint occupied() const {
-    // Overkill, but if we ever need it...
-    // guarantee(_occupied == _bm.count_one_bits(), "Check");
-    return _occupied;
-  }
-
-  void init(HeapRegion* hr, bool clear_links_to_all_list) {
-    if (clear_links_to_all_list) {
-      set_next(NULL);
-      set_prev(NULL);
-    }
-    _collision_list_next = NULL;
-    _occupied = 0;
-    _bm.clear();
-    // Make sure that the bitmap clearing above has been finished before publishing
-    // this PRT to concurrent threads.
-    OrderAccess::release_store(&_hr, hr);
-  }
-
-  void add_reference(OopOrNarrowOopStar from) {
-    add_reference_work(from, /*parallel*/ true);
-  }
-
-  void seq_add_reference(OopOrNarrowOopStar from) {
-    add_reference_work(from, /*parallel*/ false);
-  }
-
-  void add_card(CardIdx_t from_card_index) {
-    add_card_work(from_card_index, /*parallel*/ true);
-  }
-
-  void seq_add_card(CardIdx_t from_card_index) {
-    add_card_work(from_card_index, /*parallel*/ false);
-  }
-
-  // (Destructively) union the bitmap of the current table into the given
-  // bitmap (which is assumed to be of the same size.)
-  void union_bitmap_into(BitMap* bm) {
-    bm->set_union(_bm);
-  }
-
-  // Mem size in bytes.
-  size_t mem_size() const {
-    return sizeof(PerRegionTable) + _bm.size_in_words() * HeapWordSize;
-  }
-
-  // Requires "from" to be in "hr()".
-  bool contains_reference(OopOrNarrowOopStar from) const {
-    assert(hr()->is_in_reserved(from), "Precondition.");
-    size_t card_ind = pointer_delta(from, hr()->bottom(),
-                                    G1CardTable::card_size);
-    return _bm.at(card_ind);
-  }
-
-  // Bulk-free the PRTs from prt to last, assumes that they are
-  // linked together using their _next field.
-  static void bulk_free(PerRegionTable* prt, PerRegionTable* last) {
-    while (true) {
-      PerRegionTable* fl = _free_list;
-      last->set_next(fl);
-      PerRegionTable* res = Atomic::cmpxchg(prt, &_free_list, fl);
-      if (res == fl) {
-        return;
-      }
-    }
-    ShouldNotReachHere();
-  }
-
-  static void free(PerRegionTable* prt) {
-    bulk_free(prt, prt);
-  }
-
-  // Returns an initialized PerRegionTable instance.
-  static PerRegionTable* alloc(HeapRegion* hr) {
-    PerRegionTable* fl = _free_list;
-    while (fl != NULL) {
-      PerRegionTable* nxt = fl->next();
-      PerRegionTable* res = Atomic::cmpxchg(nxt, &_free_list, fl);
-      if (res == fl) {
-        fl->init(hr, true);
-        return fl;
-      } else {
-        fl = _free_list;
-      }
-    }
-    assert(fl == NULL, "Loop condition.");
-    return new PerRegionTable(hr);
-  }
-
-  PerRegionTable* next() const { return _next; }
-  void set_next(PerRegionTable* next) { _next = next; }
-  PerRegionTable* prev() const { return _prev; }
-  void set_prev(PerRegionTable* prev) { _prev = prev; }
-
-  // Accessor and Modification routines for the pointer for the
-  // singly linked collision list that links the PRTs within the
-  // OtherRegionsTable::_fine_grain_regions hash table.
-  //
-  // It might be useful to also make the collision list doubly linked
-  // to avoid iteration over the collisions list during scrubbing/deletion.
-  // OTOH there might not be many collisions.
-
-  PerRegionTable* collision_list_next() const {
-    return _collision_list_next;
-  }
-
-  void set_collision_list_next(PerRegionTable* next) {
-    _collision_list_next = next;
-  }
-
-  PerRegionTable** collision_list_next_addr() {
-    return &_collision_list_next;
-  }
-
-  static size_t fl_mem_size() {
-    PerRegionTable* cur = _free_list;
-    size_t res = 0;
-    while (cur != NULL) {
-      res += cur->mem_size();
-      cur = cur->next();
-    }
-    return res;
-  }
-
-  static void test_fl_mem_size();
-};
+  assert(fl == NULL, "Loop condition.");
+  return new PerRegionTable(hr);
+}
 
 PerRegionTable* volatile PerRegionTable::_free_list = NULL;
 
@@ -696,175 +522,3 @@
 size_t HeapRegionRemSet::strong_code_roots_mem_size() {
   return _code_roots.mem_size();
 }
-
-HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) :
-  _hrrs(hrrs),
-  _coarse_map(&hrrs->_other_regions._coarse_map),
-  _bot(hrrs->_bot),
-  _g1h(G1CollectedHeap::heap()),
-  _n_yielded_fine(0),
-  _n_yielded_coarse(0),
-  _n_yielded_sparse(0),
-  _is(Sparse),
-  _cur_region_card_offset(0),
-  // Set these values so that we increment to the first region.
-  _coarse_cur_region_index(-1),
-  _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1),
-  _fine_cur_prt(NULL),
-  _cur_card_in_prt(HeapRegion::CardsPerRegion),
-  _sparse_iter(&hrrs->_other_regions._sparse_table) {}
-
-bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
-  if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
-  // Go to the next card.
-  _coarse_cur_region_cur_card++;
-  // Was the last the last card in the current region?
-  if (_coarse_cur_region_cur_card == HeapRegion::CardsPerRegion) {
-    // Yes: find the next region.  This may leave _coarse_cur_region_index
-    // Set to the last index, in which case there are no more coarse
-    // regions.
-    _coarse_cur_region_index =
-      (int) _coarse_map->get_next_one_offset(_coarse_cur_region_index + 1);
-    if ((size_t)_coarse_cur_region_index < _coarse_map->size()) {
-      _coarse_cur_region_cur_card = 0;
-      HeapWord* r_bot =
-        _g1h->region_at((uint) _coarse_cur_region_index)->bottom();
-      _cur_region_card_offset = _bot->index_for_raw(r_bot);
-    } else {
-      return false;
-    }
-  }
-  // If we didn't return false above, then we can yield a card.
-  card_index = _cur_region_card_offset + _coarse_cur_region_cur_card;
-  return true;
-}
-
-bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) {
-  if (fine_has_next()) {
-    _cur_card_in_prt =
-      _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
-  }
-  if (_cur_card_in_prt == HeapRegion::CardsPerRegion) {
-    // _fine_cur_prt may still be NULL in case if there are not PRTs at all for
-    // the remembered set.
-    if (_fine_cur_prt == NULL || _fine_cur_prt->next() == NULL) {
-      return false;
-    }
-    PerRegionTable* next_prt = _fine_cur_prt->next();
-    switch_to_prt(next_prt);
-    _cur_card_in_prt = _fine_cur_prt->_bm.get_next_one_offset(_cur_card_in_prt + 1);
-  }
-
-  card_index = _cur_region_card_offset + _cur_card_in_prt;
-  guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion,
-            "Card index " SIZE_FORMAT " must be within the region", _cur_card_in_prt);
-  return true;
-}
-
-bool HeapRegionRemSetIterator::fine_has_next() {
-  return _cur_card_in_prt != HeapRegion::CardsPerRegion;
-}
-
-void HeapRegionRemSetIterator::switch_to_prt(PerRegionTable* prt) {
-  assert(prt != NULL, "Cannot switch to NULL prt");
-  _fine_cur_prt = prt;
-
-  HeapWord* r_bot = _fine_cur_prt->hr()->bottom();
-  _cur_region_card_offset = _bot->index_for_raw(r_bot);
-
-  // The bitmap scan for the PRT always scans from _cur_region_cur_card + 1.
-  // To avoid special-casing this start case, and not miss the first bitmap
-  // entry, initialize _cur_region_cur_card with -1 instead of 0.
-  _cur_card_in_prt = (size_t)-1;
-}
-
-bool HeapRegionRemSetIterator::has_next(size_t& card_index) {
-  switch (_is) {
-  case Sparse: {
-    if (_sparse_iter.has_next(card_index)) {
-      _n_yielded_sparse++;
-      return true;
-    }
-    // Otherwise, deliberate fall-through
-    _is = Fine;
-    PerRegionTable* initial_fine_prt = _hrrs->_other_regions._first_all_fine_prts;
-    if (initial_fine_prt != NULL) {
-      switch_to_prt(_hrrs->_other_regions._first_all_fine_prts);
-    }
-  }
-  case Fine:
-    if (fine_has_next(card_index)) {
-      _n_yielded_fine++;
-      return true;
-    }
-    // Otherwise, deliberate fall-through
-    _is = Coarse;
-  case Coarse:
-    if (coarse_has_next(card_index)) {
-      _n_yielded_coarse++;
-      return true;
-    }
-    // Otherwise...
-    break;
-  }
-  return false;
-}
-
-#ifndef PRODUCT
-void HeapRegionRemSet::test() {
-  os::sleep(Thread::current(), (jlong)5000, false);
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
-  // Run with "-XX:G1LogRSetRegionEntries=2", so that 1 and 5 end up in same
-  // hash bucket.
-  HeapRegion* hr0 = g1h->region_at(0);
-  HeapRegion* hr1 = g1h->region_at(1);
-  HeapRegion* hr2 = g1h->region_at(5);
-  HeapRegion* hr3 = g1h->region_at(6);
-  HeapRegion* hr4 = g1h->region_at(7);
-  HeapRegion* hr5 = g1h->region_at(8);
-
-  HeapWord* hr1_start = hr1->bottom();
-  HeapWord* hr1_mid = hr1_start + HeapRegion::GrainWords/2;
-  HeapWord* hr1_last = hr1->end() - 1;
-
-  HeapWord* hr2_start = hr2->bottom();
-  HeapWord* hr2_mid = hr2_start + HeapRegion::GrainWords/2;
-  HeapWord* hr2_last = hr2->end() - 1;
-
-  HeapWord* hr3_start = hr3->bottom();
-  HeapWord* hr3_mid = hr3_start + HeapRegion::GrainWords/2;
-  HeapWord* hr3_last = hr3->end() - 1;
-
-  HeapRegionRemSet* hrrs = hr0->rem_set();
-
-  // Make three references from region 0x101...
-  hrrs->add_reference((OopOrNarrowOopStar)hr1_start);
-  hrrs->add_reference((OopOrNarrowOopStar)hr1_mid);
-  hrrs->add_reference((OopOrNarrowOopStar)hr1_last);
-
-  hrrs->add_reference((OopOrNarrowOopStar)hr2_start);
-  hrrs->add_reference((OopOrNarrowOopStar)hr2_mid);
-  hrrs->add_reference((OopOrNarrowOopStar)hr2_last);
-
-  hrrs->add_reference((OopOrNarrowOopStar)hr3_start);
-  hrrs->add_reference((OopOrNarrowOopStar)hr3_mid);
-  hrrs->add_reference((OopOrNarrowOopStar)hr3_last);
-
-  // Now cause a coarsening.
-  hrrs->add_reference((OopOrNarrowOopStar)hr4->bottom());
-  hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom());
-
-  // Now, does iteration yield these three?
-  HeapRegionRemSetIterator iter(hrrs);
-  size_t sum = 0;
-  size_t card_index;
-  while (iter.has_next(card_index)) {
-    HeapWord* card_start = g1h->bot()->address_for_index(card_index);
-    tty->print_cr("  Card " PTR_FORMAT ".", p2i(card_start));
-    sum++;
-  }
-  guarantee(sum == 11 - 3 + 2048, "Failure");
-  guarantee(sum == hrrs->occupied(), "Failure");
-}
-#endif
--- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -28,6 +28,7 @@
 #include "gc/g1/g1CodeCacheRemSet.hpp"
 #include "gc/g1/g1FromCardCache.hpp"
 #include "gc/g1/sparsePRT.hpp"
+#include "utilities/bitMap.hpp"
 
 // Remembered set for a heap region.  Represent a set of "cards" that
 // contain pointers into the owner heap region.  Cards are defined somewhat
@@ -37,7 +38,6 @@
 class G1BlockOffsetTable;
 class G1CardLiveData;
 class HeapRegion;
-class HeapRegionRemSetIterator;
 class PerRegionTable;
 class SparsePRT;
 class nmethod;
@@ -67,8 +67,6 @@
 //      thinking the PRT is for a different region, does no harm.
 
 class OtherRegionsTable {
-  friend class HeapRegionRemSetIterator;
-
   G1CollectedHeap* _g1h;
   Mutex*           _m;
 
@@ -125,6 +123,9 @@
   // Create a new remembered set. The given mutex is used to ensure consistency.
   OtherRegionsTable(Mutex* m);
 
+  template <class Closure>
+  void iterate(Closure& v);
+
   // Returns the card index of the given within_region pointer relative to the bottom
   // of the given heap region.
   static CardIdx_t card_within_region(OopOrNarrowOopStar within_region, HeapRegion* hr);
@@ -157,9 +158,140 @@
   void clear();
 };
 
+class PerRegionTable: public CHeapObj<mtGC> {
+  friend class OtherRegionsTable;
+
+  HeapRegion*     _hr;
+  CHeapBitMap     _bm;
+  jint            _occupied;
+
+  // next pointer for free/allocated 'all' list
+  PerRegionTable* _next;
+
+  // prev pointer for the allocated 'all' list
+  PerRegionTable* _prev;
+
+  // next pointer in collision list
+  PerRegionTable * _collision_list_next;
+
+  // Global free list of PRTs
+  static PerRegionTable* volatile _free_list;
+
+protected:
+  PerRegionTable(HeapRegion* hr) :
+    _hr(hr),
+    _bm(HeapRegion::CardsPerRegion, mtGC),
+    _occupied(0),
+    _next(NULL), _prev(NULL),
+    _collision_list_next(NULL)
+  {}
+
+  inline void add_card_work(CardIdx_t from_card, bool par);
+
+  inline void add_reference_work(OopOrNarrowOopStar from, bool par);
+
+public:
+  // We need access in order to union things into the base table.
+  BitMap* bm() { return &_bm; }
+
+  HeapRegion* hr() const { return OrderAccess::load_acquire(&_hr); }
+
+  jint occupied() const {
+    // Overkill, but if we ever need it...
+    // guarantee(_occupied == _bm.count_one_bits(), "Check");
+    return _occupied;
+  }
+
+  void init(HeapRegion* hr, bool clear_links_to_all_list);
+
+  inline void add_reference(OopOrNarrowOopStar from);
+
+  inline void seq_add_reference(OopOrNarrowOopStar from);
+
+  inline void add_card(CardIdx_t from_card_index);
+
+  void seq_add_card(CardIdx_t from_card_index);
+
+  // (Destructively) union the bitmap of the current table into the given
+  // bitmap (which is assumed to be of the same size.)
+  void union_bitmap_into(BitMap* bm) {
+    bm->set_union(_bm);
+  }
+
+  // Mem size in bytes.
+  size_t mem_size() const {
+    return sizeof(PerRegionTable) + _bm.size_in_words() * HeapWordSize;
+  }
+
+  // Requires "from" to be in "hr()".
+  bool contains_reference(OopOrNarrowOopStar from) const {
+    assert(hr()->is_in_reserved(from), "Precondition.");
+    size_t card_ind = pointer_delta(from, hr()->bottom(),
+                                    G1CardTable::card_size);
+    return _bm.at(card_ind);
+  }
+
+  // Bulk-free the PRTs from prt to last, assumes that they are
+  // linked together using their _next field.
+  static void bulk_free(PerRegionTable* prt, PerRegionTable* last) {
+    while (true) {
+      PerRegionTable* fl = _free_list;
+      last->set_next(fl);
+      PerRegionTable* res = Atomic::cmpxchg(prt, &_free_list, fl);
+      if (res == fl) {
+        return;
+      }
+    }
+    ShouldNotReachHere();
+  }
+
+  static void free(PerRegionTable* prt) {
+    bulk_free(prt, prt);
+  }
+
+  // Returns an initialized PerRegionTable instance.
+  static PerRegionTable* alloc(HeapRegion* hr);
+
+  PerRegionTable* next() const { return _next; }
+  void set_next(PerRegionTable* next) { _next = next; }
+  PerRegionTable* prev() const { return _prev; }
+  void set_prev(PerRegionTable* prev) { _prev = prev; }
+
+  // Accessor and Modification routines for the pointer for the
+  // singly linked collision list that links the PRTs within the
+  // OtherRegionsTable::_fine_grain_regions hash table.
+  //
+  // It might be useful to also make the collision list doubly linked
+  // to avoid iteration over the collisions list during scrubbing/deletion.
+  // OTOH there might not be many collisions.
+
+  PerRegionTable* collision_list_next() const {
+    return _collision_list_next;
+  }
+
+  void set_collision_list_next(PerRegionTable* next) {
+    _collision_list_next = next;
+  }
+
+  PerRegionTable** collision_list_next_addr() {
+    return &_collision_list_next;
+  }
+
+  static size_t fl_mem_size() {
+    PerRegionTable* cur = _free_list;
+    size_t res = 0;
+    while (cur != NULL) {
+      res += cur->mem_size();
+      cur = cur->next();
+    }
+    return res;
+  }
+
+  static void test_fl_mem_size();
+};
+
 class HeapRegionRemSet : public CHeapObj<mtGC> {
   friend class VMStructs;
-  friend class HeapRegionRemSetIterator;
 
 private:
   G1BlockOffsetTable* _bot;
@@ -182,18 +314,23 @@
   // Setup sparse and fine-grain tables sizes.
   static void setup_remset_size();
 
-  bool cardset_is_empty() const {
-    return _other_regions.is_empty();
-  }
-
   bool is_empty() const {
-    return (strong_code_roots_list_length() == 0) && cardset_is_empty();
+    return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
   }
 
   bool occupancy_less_or_equal_than(size_t occ) const {
     return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ);
   }
 
+  // For each PRT in the card (remembered) set call one of the following methods
+  // of the given closure:
+  //
+  // set_full_region_dirty(uint region_idx) - pass the region index for coarse PRTs
+  // set_bitmap_dirty(uint region_idx, BitMap* bitmap) - pass the region index and bitmap for fine PRTs
+  // set_cards_dirty(uint region_idx, elem_t* cards, uint num_cards) - pass region index and cards for sparse PRTs
+  template <class Closure>
+  inline void iterate_prts(Closure& cl);
+
   size_t occupied() {
     MutexLocker x(&_m, Mutex::_no_safepoint_check_flag);
     return occupied_locked();
@@ -339,70 +476,4 @@
 #endif
 };
 
-class HeapRegionRemSetIterator : public StackObj {
-private:
-  // The region RSet over which we are iterating.
-  HeapRegionRemSet* _hrrs;
-
-  // Local caching of HRRS fields.
-  const BitMap*             _coarse_map;
-
-  G1BlockOffsetTable*       _bot;
-  G1CollectedHeap*          _g1h;
-
-  // The number of cards yielded since initialization.
-  size_t _n_yielded_fine;
-  size_t _n_yielded_coarse;
-  size_t _n_yielded_sparse;
-
-  // Indicates what granularity of table that we are currently iterating over.
-  // We start iterating over the sparse table, progress to the fine grain
-  // table, and then finish with the coarse table.
-  enum IterState {
-    Sparse,
-    Fine,
-    Coarse
-  };
-  IterState _is;
-
-  // For both Coarse and Fine remembered set iteration this contains the
-  // first card number of the heap region we currently iterate over.
-  size_t _cur_region_card_offset;
-
-  // Current region index for the Coarse remembered set iteration.
-  int    _coarse_cur_region_index;
-  size_t _coarse_cur_region_cur_card;
-
-  bool coarse_has_next(size_t& card_index);
-
-  // The PRT we are currently iterating over.
-  PerRegionTable* _fine_cur_prt;
-  // Card offset within the current PRT.
-  size_t _cur_card_in_prt;
-
-  // Update internal variables when switching to the given PRT.
-  void switch_to_prt(PerRegionTable* prt);
-  bool fine_has_next();
-  bool fine_has_next(size_t& card_index);
-
-  // The Sparse remembered set iterator.
-  SparsePRTIter _sparse_iter;
-
-public:
-  HeapRegionRemSetIterator(HeapRegionRemSet* hrrs);
-
-  // If there remains one or more cards to be yielded, returns true and
-  // sets "card_index" to one of those cards (which is then considered
-  // yielded.)   Otherwise, returns false (and leaves "card_index"
-  // undefined.)
-  bool has_next(size_t& card_index);
-
-  size_t n_yielded_fine() { return _n_yielded_fine; }
-  size_t n_yielded_coarse() { return _n_yielded_coarse; }
-  size_t n_yielded_sparse() { return _n_yielded_sparse; }
-  size_t n_yielded() {
-    return n_yielded_fine() + n_yielded_coarse() + n_yielded_sparse();
-  }
-};
-
 #endif // SHARE_GC_G1_HEAPREGIONREMSET_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_HEAPREGIONREMSET_INLINE_HPP
+#define SHARE_VM_GC_G1_HEAPREGIONREMSET_INLINE_HPP
+
+#include "gc/g1/heapRegion.inline.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/sparsePRT.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+template <class Closure>
+inline void HeapRegionRemSet::iterate_prts(Closure& cl) {
+  _other_regions.iterate(cl);
+}
+
+inline void PerRegionTable::add_card_work(CardIdx_t from_card, bool par) {
+  if (!_bm.at(from_card)) {
+    if (par) {
+      if (_bm.par_set_bit(from_card)) {
+        Atomic::inc(&_occupied);
+      }
+    } else {
+      _bm.set_bit(from_card);
+      _occupied++;
+    }
+  }
+}
+
+inline void PerRegionTable::add_reference_work(OopOrNarrowOopStar from, bool par) {
+  // Must make this robust in case "from" is not in "_hr", because of
+  // concurrency.
+
+  HeapRegion* loc_hr = hr();
+  // If the test below fails, then this table was reused concurrently
+  // with this operation.  This is OK, since the old table was coarsened,
+  // and adding a bit to the new table is never incorrect.
+  if (loc_hr->is_in_reserved(from)) {
+    CardIdx_t from_card = OtherRegionsTable::card_within_region(from, loc_hr);
+    add_card_work(from_card, par);
+  }
+}
+
+inline void PerRegionTable::add_card(CardIdx_t from_card_index) {
+  add_card_work(from_card_index, /*parallel*/ true);
+}
+
+inline void PerRegionTable::seq_add_card(CardIdx_t from_card_index) {
+  add_card_work(from_card_index, /*parallel*/ false);
+}
+
+inline void PerRegionTable::add_reference(OopOrNarrowOopStar from) {
+  add_reference_work(from, /*parallel*/ true);
+}
+
+inline void PerRegionTable::seq_add_reference(OopOrNarrowOopStar from) {
+  add_reference_work(from, /*parallel*/ false);
+}
+
+inline void PerRegionTable::init(HeapRegion* hr, bool clear_links_to_all_list) {
+  if (clear_links_to_all_list) {
+    set_next(NULL);
+    set_prev(NULL);
+  }
+  _collision_list_next = NULL;
+  _occupied = 0;
+  _bm.clear();
+  // Make sure that the bitmap clearing above has been finished before publishing
+  // this PRT to concurrent threads.
+  OrderAccess::release_store(&_hr, hr);
+}
+
+template <class Closure>
+void OtherRegionsTable::iterate(Closure& cl) {
+  if (_n_coarse_entries > 0) {
+    BitMap::idx_t cur = _coarse_map.get_next_one_offset(0);
+    while (cur != _coarse_map.size()) {
+      cl.next_coarse_prt((uint)cur);
+      cur = _coarse_map.get_next_one_offset(cur + 1);
+    }
+  }
+  {
+    PerRegionTable* cur = _first_all_fine_prts;
+    while (cur != NULL) {
+      cl.next_fine_prt(cur->hr()->hrm_index(), cur->bm());
+      cur = cur->next();
+    }
+  }
+  {
+    SparsePRTBucketIter iter(&_sparse_table);
+    SparsePRTEntry* cur;
+    while (iter.has_next(cur)) {
+      cl.next_sparse_prt(cur->r_ind(), cur->cards(), cur->num_valid_cards());
+    }
+  }
+}
+
+#endif // SHARE_VM_GC_G1_HEAPREGIONREMSET_INLINE_HPP
--- a/src/hotspot/share/gc/g1/sparsePRT.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/sparsePRT.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -275,6 +275,19 @@
   return false;
 }
 
+bool RSHashTableBucketIter::has_next(SparsePRTEntry*& entry) {
+  while (_bl_ind == RSHashTable::NullEntry)  {
+    if (_tbl_ind == (int)_rsht->capacity() - 1) {
+      return false;
+    }
+    _tbl_ind++;
+    _bl_ind = _rsht->_buckets[_tbl_ind];
+  }
+  entry = _rsht->entry(_bl_ind);
+  _bl_ind = entry->next_index();
+  return true;
+}
+
 bool RSHashTable::contains_card(RegionIdx_t region_index, CardIdx_t card_index) const {
   SparsePRTEntry* e = get_entry(region_index);
   return (e != NULL && e->contains_card(card_index));
--- a/src/hotspot/share/gc/g1/sparsePRT.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/g1/sparsePRT.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -38,10 +38,11 @@
 // that might contain pointers into the owner region.
 
 class SparsePRTEntry: public CHeapObj<mtGC> {
-private:
+public:
   // The type of a card entry.
   typedef uint16_t card_elem_t;
 
+private:
   // We need to make sizeof(SparsePRTEntry) an even multiple of maximum member size,
   // in order to force correct alignment that could otherwise cause SIGBUS errors
   // when reading the member variables. This calculates the minimum number of card
@@ -96,6 +97,8 @@
   // Copy the current entry's cards into the "_card" array of "e."
   inline void copy_cards(SparsePRTEntry* e) const;
 
+  card_elem_t* cards() { return _cards; }
+
   inline CardIdx_t card(int i) const {
     assert(i >= 0, "must be nonnegative");
     assert(i < cards_num(), "range checking");
@@ -106,7 +109,7 @@
 class RSHashTable : public CHeapObj<mtGC> {
 
   friend class RSHashTableIter;
-
+  friend class RSHashTableBucketIter;
 
   // Inverse maximum hash table occupancy used.
   static float TableOccupancyFactor;
@@ -209,12 +212,29 @@
   bool has_next(size_t& card_index);
 };
 
+// This is embedded in HRRS iterator.
+class RSHashTableBucketIter {
+  int _tbl_ind;         // [-1, 0.._rsht->_capacity)
+  int _bl_ind;          // [-1, 0.._rsht->_capacity)
+
+  RSHashTable* _rsht;
+
+public:
+  RSHashTableBucketIter(RSHashTable* rsht) :
+    _tbl_ind(0),
+    _bl_ind(rsht->_buckets[_tbl_ind]),
+    _rsht(rsht) { }
+
+  bool has_next(SparsePRTEntry*& entry);
+};
+
 // Concurrent access to a SparsePRT must be serialized by some external mutex.
 
 class SparsePRTIter;
 
 class SparsePRT {
   friend class SparsePRTIter;
+  friend class SparsePRTBucketIter;
 
   RSHashTable* _table;
 
@@ -262,4 +282,14 @@
   }
 };
 
+class SparsePRTBucketIter: public RSHashTableBucketIter {
+public:
+  SparsePRTBucketIter(const SparsePRT* sprt) :
+    RSHashTableBucketIter(sprt->_table) {}
+
+  bool has_next(SparsePRTEntry*& entry) {
+    return RSHashTableBucketIter::has_next(entry);
+  }
+};
+
 #endif // SHARE_GC_G1_SPARSEPRT_HPP
--- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -259,7 +259,6 @@
 
     BiasedLocking::restore_marks();
     heap->prune_scavengable_nmethods();
-    JvmtiExport::gc_epilogue();
 
 #if COMPILER2_OR_JVMCI
     DerivedPointerTable::update_pointers();
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -1064,7 +1064,6 @@
   MetaspaceUtils::verify_metrics();
 
   heap->prune_scavengable_nmethods();
-  JvmtiExport::gc_epilogue();
 
 #if COMPILER2_OR_JVMCI
   DerivedPointerTable::update_pointers();
--- a/src/hotspot/share/gc/serial/genMarkSweep.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -129,7 +129,6 @@
   }
 
   gch->prune_scavengable_nmethods();
-  JvmtiExport::gc_epilogue();
 
   // refs processing: clean slate
   set_ref_processor(NULL);
--- a/src/hotspot/share/gc/shared/cardTable.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/cardTable.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -103,15 +103,11 @@
 
   enum CardValues {
     clean_card                  = (CardValue)-1,
-    // The mask contains zeros in places for all other values.
-    clean_card_mask             = clean_card - 31,
 
     dirty_card                  =  0,
     precleaned_card             =  1,
-    claimed_card                =  2,
-    deferred_card               =  4,
-    last_card                   =  8,
-    CT_MR_BS_last_reserved      = 16
+    last_card                   =  2,
+    CT_MR_BS_last_reserved      =  4
   };
 
   // a word's worth (row) of clean card values
@@ -242,11 +238,8 @@
   };
 
   static CardValue clean_card_val()          { return clean_card; }
-  static CardValue clean_card_mask_val()     { return clean_card_mask; }
   static CardValue dirty_card_val()          { return dirty_card; }
-  static CardValue claimed_card_val()        { return claimed_card; }
   static CardValue precleaned_card_val()     { return precleaned_card; }
-  static CardValue deferred_card_val()       { return deferred_card; }
   static intptr_t clean_card_row_val()   { return clean_card_row; }
 
   // Card marking array base (adjusted for heap low boundary)
--- a/src/hotspot/share/gc/shared/ptrQueue.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/ptrQueue.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -250,28 +250,15 @@
   return removed;
 }
 
-PtrQueueSet::PtrQueueSet(bool notify_when_complete) :
+PtrQueueSet::PtrQueueSet() :
   _allocator(NULL),
-  _cbl_mon(NULL),
-  _completed_buffers_head(NULL),
-  _completed_buffers_tail(NULL),
-  _n_completed_buffers(0),
-  _process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever),
-  _process_completed_buffers(false),
-  _notify_when_complete(notify_when_complete),
   _all_active(false)
 {}
 
-PtrQueueSet::~PtrQueueSet() {
-  // There are presently only a couple (derived) instances ever
-  // created, and they are permanent, so no harm currently done by
-  // doing nothing here.
-}
+PtrQueueSet::~PtrQueueSet() {}
 
-void PtrQueueSet::initialize(Monitor* cbl_mon,
-                             BufferNode::Allocator* allocator) {
-  assert(cbl_mon != NULL && allocator != NULL, "Init order issue?");
-  _cbl_mon = cbl_mon;
+void PtrQueueSet::initialize(BufferNode::Allocator* allocator) {
+  assert(allocator != NULL, "Init order issue?");
   _allocator = allocator;
 }
 
@@ -284,121 +271,3 @@
   _allocator->release(node);
 }
 
-void PtrQueueSet::enqueue_completed_buffer(BufferNode* cbn) {
-  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-  cbn->set_next(NULL);
-  if (_completed_buffers_tail == NULL) {
-    assert(_completed_buffers_head == NULL, "Well-formedness");
-    _completed_buffers_head = cbn;
-    _completed_buffers_tail = cbn;
-  } else {
-    _completed_buffers_tail->set_next(cbn);
-    _completed_buffers_tail = cbn;
-  }
-  _n_completed_buffers++;
-
-  if (!_process_completed_buffers &&
-      (_n_completed_buffers > _process_completed_buffers_threshold)) {
-    _process_completed_buffers = true;
-    if (_notify_when_complete) {
-      _cbl_mon->notify();
-    }
-  }
-  assert_completed_buffers_list_len_correct_locked();
-}
-
-BufferNode* PtrQueueSet::get_completed_buffer(size_t stop_at) {
-  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-
-  if (_n_completed_buffers <= stop_at) {
-    return NULL;
-  }
-
-  assert(_n_completed_buffers > 0, "invariant");
-  assert(_completed_buffers_head != NULL, "invariant");
-  assert(_completed_buffers_tail != NULL, "invariant");
-
-  BufferNode* bn = _completed_buffers_head;
-  _n_completed_buffers--;
-  _completed_buffers_head = bn->next();
-  if (_completed_buffers_head == NULL) {
-    assert(_n_completed_buffers == 0, "invariant");
-    _completed_buffers_tail = NULL;
-    _process_completed_buffers = false;
-  }
-  assert_completed_buffers_list_len_correct_locked();
-  bn->set_next(NULL);
-  return bn;
-}
-
-void PtrQueueSet::abandon_completed_buffers() {
-  BufferNode* buffers_to_delete = NULL;
-  {
-    MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-    buffers_to_delete = _completed_buffers_head;
-    _completed_buffers_head = NULL;
-    _completed_buffers_tail = NULL;
-    _n_completed_buffers = 0;
-    _process_completed_buffers = false;
-  }
-  while (buffers_to_delete != NULL) {
-    BufferNode* bn = buffers_to_delete;
-    buffers_to_delete = bn->next();
-    bn->set_next(NULL);
-    deallocate_buffer(bn);
-  }
-}
-
-#ifdef ASSERT
-
-void PtrQueueSet::assert_completed_buffers_list_len_correct_locked() {
-  assert_lock_strong(_cbl_mon);
-  size_t n = 0;
-  for (BufferNode* bn = _completed_buffers_head; bn != NULL; bn = bn->next()) {
-    ++n;
-  }
-  assert(n == _n_completed_buffers,
-         "Completed buffer length is wrong: counted: " SIZE_FORMAT
-         ", expected: " SIZE_FORMAT, n, _n_completed_buffers);
-}
-
-#endif // ASSERT
-
-// Merge lists of buffers. Notify the processing threads.
-// The source queue is emptied as a result. The queues
-// must share the monitor.
-void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
-  assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
-  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-  if (_completed_buffers_tail == NULL) {
-    assert(_completed_buffers_head == NULL, "Well-formedness");
-    _completed_buffers_head = src->_completed_buffers_head;
-    _completed_buffers_tail = src->_completed_buffers_tail;
-  } else {
-    assert(_completed_buffers_head != NULL, "Well formedness");
-    if (src->_completed_buffers_head != NULL) {
-      _completed_buffers_tail->set_next(src->_completed_buffers_head);
-      _completed_buffers_tail = src->_completed_buffers_tail;
-    }
-  }
-  _n_completed_buffers += src->_n_completed_buffers;
-
-  src->_n_completed_buffers = 0;
-  src->_completed_buffers_head = NULL;
-  src->_completed_buffers_tail = NULL;
-  src->_process_completed_buffers = false;
-
-  assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
-         _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
-         "Sanity");
-  assert_completed_buffers_list_len_correct_locked();
-}
-
-void PtrQueueSet::notify_if_necessary() {
-  MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-  if (_n_completed_buffers > _process_completed_buffers_threshold) {
-    _process_completed_buffers = true;
-    if (_notify_when_complete)
-      _cbl_mon->notify();
-  }
-}
--- a/src/hotspot/share/gc/shared/ptrQueue.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/ptrQueue.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -296,35 +296,16 @@
 class PtrQueueSet {
   BufferNode::Allocator* _allocator;
 
-  Monitor* _cbl_mon;  // Protects the fields below.
-  BufferNode* _completed_buffers_head;
-  BufferNode* _completed_buffers_tail;
-  volatile size_t _n_completed_buffers;
-
-  size_t _process_completed_buffers_threshold;
-  volatile bool _process_completed_buffers;
-
-  // If true, notify_all on _cbl_mon when the threshold is reached.
-  bool _notify_when_complete;
-
-  void assert_completed_buffers_list_len_correct_locked() NOT_DEBUG_RETURN;
-
 protected:
   bool _all_active;
 
   // Create an empty ptr queue set.
-  PtrQueueSet(bool notify_when_complete = false);
+  PtrQueueSet();
   ~PtrQueueSet();
 
   // Because of init-order concerns, we can't pass these as constructor
   // arguments.
-  void initialize(Monitor* cbl_mon, BufferNode::Allocator* allocator);
-
-  // For (unlocked!) iteration over the completed buffers.
-  BufferNode* completed_buffers_head() const { return _completed_buffers_head; }
-
-  // Deallocate all of the completed buffers.
-  void abandon_completed_buffers();
+  void initialize(BufferNode::Allocator* allocator);
 
 public:
 
@@ -339,38 +320,13 @@
   // is ready to be processed by the collector.  It need not be full.
 
   // Adds node to the completed buffer list.
-  void enqueue_completed_buffer(BufferNode* node);
-
-  // If the number of completed buffers is > stop_at, then remove and
-  // return a completed buffer from the list.  Otherwise, return NULL.
-  BufferNode* get_completed_buffer(size_t stop_at = 0);
-
-  bool process_completed_buffers() { return _process_completed_buffers; }
-  void set_process_completed_buffers(bool x) { _process_completed_buffers = x; }
+  virtual void enqueue_completed_buffer(BufferNode* node) = 0;
 
   bool is_active() { return _all_active; }
 
   size_t buffer_size() const {
     return _allocator->buffer_size();
   }
-
-  // Get/Set the number of completed buffers that triggers log processing.
-  // Log processing should be done when the number of buffers exceeds the
-  // threshold.
-  void set_process_completed_buffers_threshold(size_t sz) {
-    _process_completed_buffers_threshold = sz;
-  }
-  size_t process_completed_buffers_threshold() const {
-    return _process_completed_buffers_threshold;
-  }
-  static const size_t ProcessCompletedBuffersThresholdNever = ~size_t(0);
-
-  size_t completed_buffers_num() const { return _n_completed_buffers; }
-
-  void merge_bufferlists(PtrQueueSet* src);
-
-  // Notify the consumer if the number of buffers crossed the threshold
-  void notify_if_necessary();
 };
 
 #endif // SHARE_GC_SHARED_PTRQUEUE_HPP
--- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -28,12 +28,15 @@
 #include "logging/log.hpp"
 #include "memory/allocation.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.hpp"
 #include "runtime/os.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/thread.hpp"
 #include "runtime/threadSMR.hpp"
 #include "runtime/vmThread.hpp"
+#include "utilities/globalCounter.inline.hpp"
 
 SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset) :
   // SATB queues are only active during marking cycles. We create
@@ -107,15 +110,66 @@
 
 SATBMarkQueueSet::SATBMarkQueueSet() :
   PtrQueueSet(),
+  _list(),
+  _count_and_process_flag(0),
+  _process_completed_buffers_threshold(SIZE_MAX),
   _buffer_enqueue_threshold(0)
 {}
 
-void SATBMarkQueueSet::initialize(Monitor* cbl_mon,
-                                  BufferNode::Allocator* allocator,
+SATBMarkQueueSet::~SATBMarkQueueSet() {
+  abandon_completed_buffers();
+}
+
+// _count_and_process_flag has flag in least significant bit, count in
+// remaining bits.  _process_completed_buffers_threshold is scaled
+// accordingly, with the lsbit set, so a _count_and_process_flag value
+// is directly comparable with the recorded threshold value.  The
+// process flag is set whenever the count exceeds the threshold, and
+// remains set until the count is reduced to zero.
+
+// Increment count.  If count > threshold, set flag, else maintain flag.
+static void increment_count(volatile size_t* cfptr, size_t threshold) {
+  size_t old;
+  size_t value = Atomic::load(cfptr);
+  do {
+    old = value;
+    value += 2;
+    assert(value > old, "overflow");
+    if (value > threshold) value |= 1;
+    value = Atomic::cmpxchg(value, cfptr, old);
+  } while (value != old);
+}
+
+// Decrement count.  If count == 0, clear flag, else maintain flag.
+static void decrement_count(volatile size_t* cfptr) {
+  size_t old;
+  size_t value = Atomic::load(cfptr);
+  do {
+    assert((value >> 1) != 0, "underflow");
+    old = value;
+    value -= 2;
+    if (value <= 1) value = 0;
+    value = Atomic::cmpxchg(value, cfptr, old);
+  } while (value != old);
+}
+
+// Scale requested threshold to align with count field.  If scaling
+// overflows, just use max value.  Set process flag field to make
+// comparison in increment_count exact.
+static size_t scale_threshold(size_t value) {
+  size_t scaled_value = value << 1;
+  if ((scaled_value >> 1) != value) {
+    scaled_value = SIZE_MAX;
+  }
+  return scaled_value | 1;
+}
+
+void SATBMarkQueueSet::initialize(BufferNode::Allocator* allocator,
                                   size_t process_completed_buffers_threshold,
                                   uint buffer_enqueue_threshold_percentage) {
-  PtrQueueSet::initialize(cbl_mon, allocator);
-  set_process_completed_buffers_threshold(process_completed_buffers_threshold);
+  PtrQueueSet::initialize(allocator);
+  _process_completed_buffers_threshold =
+    scale_threshold(process_completed_buffers_threshold);
   assert(buffer_size() != 0, "buffer size not initialized");
   // Minimum threshold of 1 ensures enqueuing of completely full buffers.
   size_t size = buffer_size();
@@ -207,6 +261,38 @@
   }
 }
 
+// SATB buffer life-cycle - Per-thread queues obtain buffers from the
+// qset's buffer allocator, fill them, and push them onto the qset's
+// list.  The GC concurrently pops buffers from the qset, processes
+// them, and returns them to the buffer allocator for re-use.  Both
+// the allocator and the qset use lock-free stacks.  The ABA problem
+// is solved by having both allocation pops and GC pops performed
+// within GlobalCounter critical sections, while the return of buffers
+// to the allocator performs a GlobalCounter synchronize before
+// pushing onto the allocator's list.
+
+void SATBMarkQueueSet::enqueue_completed_buffer(BufferNode* node) {
+  assert(node != NULL, "precondition");
+  // Increment count and update flag appropriately.  Done before
+  // pushing buffer so count is always at least the actual number in
+  // the list, and decrement never underflows.
+  increment_count(&_count_and_process_flag, _process_completed_buffers_threshold);
+  _list.push(*node);
+}
+
+BufferNode* SATBMarkQueueSet::get_completed_buffer() {
+  BufferNode* node;
+  {
+    GlobalCounter::CriticalSection cs(Thread::current());
+    node = _list.pop();
+  }
+  if (node != NULL) {
+    // Got a buffer so decrement count and update flag appropriately.
+    decrement_count(&_count_and_process_flag);
+  }
+  return node;
+}
+
 #ifndef PRODUCT
 // Helpful for debugging
 
@@ -219,7 +305,7 @@
   tty->cr();
   tty->print_cr("SATB BUFFERS [%s]", msg);
 
-  BufferNode* nd = completed_buffers_head();
+  BufferNode* nd = _list.top();
   int i = 0;
   while (nd != NULL) {
     void** buf = BufferNode::make_buffer_from_node(nd);
@@ -248,6 +334,17 @@
 }
 #endif // PRODUCT
 
+void SATBMarkQueueSet::abandon_completed_buffers() {
+  Atomic::store(size_t(0), &_count_and_process_flag);
+  BufferNode* buffers_to_delete = _list.pop_all();
+  while (buffers_to_delete != NULL) {
+    BufferNode* bn = buffers_to_delete;
+    buffers_to_delete = bn->next();
+    bn->set_next(NULL);
+    deallocate_buffer(bn);
+  }
+}
+
 void SATBMarkQueueSet::abandon_partial_marking() {
   assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
   abandon_completed_buffers();
--- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -27,6 +27,7 @@
 
 #include "gc/shared/ptrQueue.hpp"
 #include "memory/allocation.hpp"
+#include "memory/padded.hpp"
 
 class Thread;
 class Monitor;
@@ -93,7 +94,17 @@
 };
 
 class SATBMarkQueueSet: public PtrQueueSet {
+
+  DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+  PaddedEnd<BufferNode::Stack> _list;
+  volatile size_t _count_and_process_flag;
+  // These are rarely (if ever) changed, so same cache line as count.
+  size_t _process_completed_buffers_threshold;
   size_t _buffer_enqueue_threshold;
+  DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 3 * sizeof(size_t));
+
+  BufferNode* get_completed_buffer();
+  void abandon_completed_buffers();
 
 #ifdef ASSERT
   void dump_active_states(bool expected_active);
@@ -102,15 +113,14 @@
 
 protected:
   SATBMarkQueueSet();
-  ~SATBMarkQueueSet() {}
+  ~SATBMarkQueueSet();
 
   template<typename Filter>
   void apply_filter(Filter filter, SATBMarkQueue* queue) {
     queue->apply_filter(filter);
   }
 
-  void initialize(Monitor* cbl_mon,
-                  BufferNode::Allocator* allocator,
+  void initialize(BufferNode::Allocator* allocator,
                   size_t process_completed_buffers_threshold,
                   uint buffer_enqueue_threshold_percentage);
 
@@ -132,6 +142,19 @@
   // buffer; the leading entries may be excluded due to filtering.
   bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
 
+  virtual void enqueue_completed_buffer(BufferNode* node);
+
+  // The number of buffers in the list.  Racy and not updated atomically
+  // with the set of completed buffers.
+  size_t completed_buffers_num() const {
+    return _count_and_process_flag >> 1;
+  }
+
+  // Return true if completed buffers should be processed.
+  bool process_completed_buffers() const {
+    return (_count_and_process_flag & 1) != 0;
+  }
+
 #ifndef PRODUCT
   // Helpful for debugging
   void print_all(const char* msg);
--- a/src/hotspot/share/gc/shared/workerDataArray.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/workerDataArray.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -34,7 +34,7 @@
 class WorkerDataArray  : public CHeapObj<mtGC> {
   friend class WDAPrinter;
 public:
-  static const uint MaxThreadWorkItems = 5;
+  static const uint MaxThreadWorkItems = 6;
 private:
   T*          _data;
   uint        _length;
--- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -101,7 +101,7 @@
 template <typename T>
 void WorkerDataArray<T>::add(uint worker_i, T value) {
   assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length);
-  assert(_data[worker_i] != uninitialized(), "No data to add to for worker %d", worker_i);
+  assert(_data[worker_i] != uninitialized(), "No data to add to %s for worker %d", _title, worker_i);
   _data[worker_i] += value;
 }
 
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -348,7 +348,6 @@
   // The call below uses stuff (the SATB* things) that are in G1, but probably
   // belong into a shared location.
   ShenandoahBarrierSet::satb_mark_queue_set().initialize(this,
-                                                         SATB_Q_CBL_mon,
                                                          20 /* G1SATBProcessCompletedThreshold */,
                                                          60 /* G1SATBBufferEnqueueingThresholdPercent */);
 
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -175,8 +175,6 @@
     _preserved_marks->restore(&exec);
     BiasedLocking::restore_marks();
     _preserved_marks->reclaim();
-
-    JvmtiExport::gc_epilogue();
   }
 
   // Resize metaspace
--- a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -33,11 +33,9 @@
 {}
 
 void ShenandoahSATBMarkQueueSet::initialize(ShenandoahHeap* const heap,
-                                            Monitor* cbl_mon,
                                             int process_completed_threshold,
                                             uint buffer_enqueue_threshold_percentage) {
-  SATBMarkQueueSet::initialize(cbl_mon,
-                               &_satb_mark_queue_buffer_allocator,
+  SATBMarkQueueSet::initialize(&_satb_mark_queue_buffer_allocator,
                                process_completed_threshold,
                                buffer_enqueue_threshold_percentage);
   _heap = heap;
--- a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -44,7 +44,6 @@
   ShenandoahSATBMarkQueueSet();
 
   void initialize(ShenandoahHeap* const heap,
-                  Monitor* cbl_mon,
                   int process_completed_threshold,
                   uint buffer_enqueue_threshold_percentage);
 
--- a/src/hotspot/share/gc/z/zRootsIterator.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/gc/z/zRootsIterator.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -198,7 +198,6 @@
   } else {
     ZNMethod::oops_do_end();
   }
-  JvmtiExport::gc_epilogue();
 
   COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
   Threads::assert_all_threads_claimed();
--- a/src/hotspot/share/opto/type.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/opto/type.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -730,8 +730,11 @@
   // Since we just discovered a new Type, compute its dual right now.
   assert( !_dual, "" );         // No dual yet
   _dual = xdual();              // Compute the dual
-  if( cmp(this,_dual)==0 ) {    // Handle self-symmetric
-    _dual = this;
+  if (cmp(this, _dual) == 0) {  // Handle self-symmetric
+    if (_dual != this) {
+      delete _dual;
+      _dual = this;
+    }
     return this;
   }
   assert( !_dual->_dual, "" );  // No reverse dual yet
--- a/src/hotspot/share/prims/jvmtiExport.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiExport.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -2615,10 +2615,6 @@
   JvmtiTagMap::weak_oops_do(is_alive, f);
 }
 
-void JvmtiExport::gc_epilogue() {
-  JvmtiCurrentBreakpoints::gc_epilogue();
-}
-
 // Onload raw monitor transition.
 void JvmtiExport::transition_pending_onload_raw_monitors() {
   JvmtiPendingMonitors::transition_raw_monitors();
--- a/src/hotspot/share/prims/jvmtiExport.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiExport.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -388,7 +388,6 @@
 
   static void oops_do(OopClosure* f) NOT_JVMTI_RETURN;
   static void weak_oops_do(BoolObjectClosure* b, OopClosure* f) NOT_JVMTI_RETURN;
-  static void gc_epilogue() NOT_JVMTI_RETURN;
 
   static void transition_pending_onload_raw_monitors() NOT_JVMTI_RETURN;
 
--- a/src/hotspot/share/prims/jvmtiImpl.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiImpl.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -225,13 +225,6 @@
   }
 }
 
-void GrowableCache::gc_epilogue() {
-  int len = _elements->length();
-  for (int i=0; i<len; i++) {
-    _cache[i] = _elements->at(i)->getCacheValue();
-  }
-}
-
 //
 // class JvmtiBreakpoint
 //
@@ -389,10 +382,6 @@
   _bps.metadata_do(f);
 }
 
-void JvmtiBreakpoints::gc_epilogue() {
-  _bps.gc_epilogue();
-}
-
 void JvmtiBreakpoints::print() {
 #ifndef PRODUCT
   LogTarget(Trace, jvmti) log;
@@ -514,12 +503,6 @@
   }
 }
 
-void JvmtiCurrentBreakpoints::gc_epilogue() {
-  if (_jvmti_breakpoints != NULL) {
-    _jvmti_breakpoints->gc_epilogue();
-  }
-}
-
 ///////////////////////////////////////////////////////////////
 //
 // class VM_GetOrSetLocal
--- a/src/hotspot/share/prims/jvmtiImpl.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/prims/jvmtiImpl.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -120,8 +120,6 @@
   void oops_do(OopClosure* f);
   // walk metadata to preserve for RedefineClasses
   void metadata_do(void f(Metadata*));
-  // update the cache after a full gc
-  void gc_epilogue();
 };
 
 
@@ -154,7 +152,6 @@
   void clear()                          { _cache.clear(); }
   void oops_do(OopClosure* f)           { _cache.oops_do(f); }
   void metadata_do(void f(Metadata*))   { _cache.metadata_do(f); }
-  void gc_epilogue()                    { _cache.gc_epilogue(); }
 };
 
 
@@ -257,7 +254,6 @@
   int  set(JvmtiBreakpoint& bp);
   int  clear(JvmtiBreakpoint& bp);
   void clearall_in_class_at_safepoint(Klass* klass);
-  void gc_epilogue();
 };
 
 
@@ -299,7 +295,6 @@
 
   static void oops_do(OopClosure* f);
   static void metadata_do(void f(Metadata*)) NOT_JVMTI_RETURN;
-  static void gc_epilogue();
 };
 
 ///////////////////////////////////////////////////////////////
--- a/src/hotspot/share/runtime/arguments.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/arguments.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -1815,6 +1815,10 @@
       // was not specified.
       if (reasonable_max > max_coop_heap) {
         if (FLAG_IS_ERGO(UseCompressedOops) && override_coop_limit) {
+          log_info(cds)("UseCompressedOops and UseCompressedClassPointers have been disabled due to"
+            " max heap " SIZE_FORMAT " > compressed oop heap " SIZE_FORMAT ". "
+            "Please check the setting of MaxRAMPercentage %5.2f."
+            ,(size_t)reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage);
           FLAG_SET_ERGO(UseCompressedOops, false);
           FLAG_SET_ERGO(UseCompressedClassPointers, false);
         } else {
--- a/src/hotspot/share/runtime/biasedLocking.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/biasedLocking.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -548,7 +548,7 @@
       if (biased_locker != NULL) {
         _biased_locker_id = JFR_THREAD_ID(biased_locker);
       }
-      _safepoint_id = SafepointSynchronize::safepoint_counter();
+      _safepoint_id = SafepointSynchronize::safepoint_id();
       clean_up_cached_monitor_info();
       return;
     } else {
@@ -589,7 +589,7 @@
 
   virtual void doit() {
     _status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread);
-    _safepoint_id = SafepointSynchronize::safepoint_counter();
+    _safepoint_id = SafepointSynchronize::safepoint_id();
     clean_up_cached_monitor_info();
   }
 
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -82,7 +82,6 @@
 Monitor* CGC_lock                     = NULL;
 Monitor* STS_lock                     = NULL;
 Monitor* FullGCCount_lock             = NULL;
-Monitor* SATB_Q_CBL_mon               = NULL;
 Monitor* DirtyCardQ_CBL_mon           = NULL;
 Mutex*   Shared_DirtyCardQ_lock       = NULL;
 Mutex*   MarkStackFreeList_lock       = NULL;
@@ -228,8 +227,6 @@
 
   def(FullGCCount_lock             , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_never);      // in support of ExplicitGCInvokesConcurrent
   if (UseG1GC) {
-    def(SATB_Q_CBL_mon             , PaddedMonitor, access,      true,  Monitor::_safepoint_check_never);
-
     def(DirtyCardQ_CBL_mon         , PaddedMonitor, access,      true,  Monitor::_safepoint_check_never);
     def(Shared_DirtyCardQ_lock     , PaddedMutex  , access + 1,  true,  Monitor::_safepoint_check_never);
 
@@ -246,8 +243,6 @@
     def(MonitoringSupport_lock     , PaddedMutex  , native   ,   true,  Monitor::_safepoint_check_never);      // used for serviceability monitoring support
   }
   if (UseShenandoahGC) {
-    def(SATB_Q_CBL_mon             , PaddedMonitor, access,      true,  Monitor::_safepoint_check_never);
-
     def(StringDedupQueue_lock      , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_never);
     def(StringDedupTable_lock      , PaddedMutex  , leaf,        true,  Monitor::_safepoint_check_never);
   }
--- a/src/hotspot/share/runtime/mutexLocker.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -77,8 +77,6 @@
                                                  // fore- & background GC threads.
 extern Monitor* STS_lock;                        // used for joining/leaving SuspendibleThreadSet.
 extern Monitor* FullGCCount_lock;                // in support of "concurrent" full gc
-extern Monitor* SATB_Q_CBL_mon;                  // Protects SATB Q
-                                                 // completed buffer queue.
 extern Monitor* DirtyCardQ_CBL_mon;              // Protects dirty card Q
                                                  // completed buffer queue.
 extern Mutex*   Shared_DirtyCardQ_lock;          // Lock protecting dirty card
--- a/src/hotspot/share/runtime/safepoint.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/safepoint.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -118,12 +118,22 @@
   }
 }
 
+// SafepointCheck
+SafepointStateTracker::SafepointStateTracker(uint64_t safepoint_id, bool at_safepoint)
+  : _safepoint_id(safepoint_id), _at_safepoint(at_safepoint) {}
+
+bool SafepointStateTracker::safepoint_state_changed() {
+  return _safepoint_id != SafepointSynchronize::safepoint_id() ||
+    _at_safepoint != SafepointSynchronize::is_at_safepoint();
+}
+
 // --------------------------------------------------------------------------------------------------
 // Implementation of Safepoint begin/end
 
 SafepointSynchronize::SynchronizeState volatile SafepointSynchronize::_state = SafepointSynchronize::_not_synchronized;
 int SafepointSynchronize::_waiting_to_block = 0;
 volatile uint64_t SafepointSynchronize::_safepoint_counter = 0;
+uint64_t SafepointSynchronize::_safepoint_id = 0;
 const uint64_t SafepointSynchronize::InactiveSafepointCounter = 0;
 int SafepointSynchronize::_current_jni_active_count = 0;
 
@@ -154,7 +164,7 @@
   --_waiting_to_block;
 }
 
-static bool thread_not_running(ThreadSafepointState *cur_state) {
+bool SafepointSynchronize::thread_not_running(ThreadSafepointState *cur_state) {
   if (!cur_state->is_running()) {
     return true;
   }
@@ -408,6 +418,9 @@
 
   OrderAccess::fence();
 
+  // Set the new id
+  ++_safepoint_id;
+
 #ifdef ASSERT
   // Make sure all the threads were visited.
   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) {
@@ -419,7 +432,7 @@
   GCLocker::set_jni_lock_count(_current_jni_active_count);
 
   post_safepoint_synchronize_event(sync_event,
-                                   _safepoint_counter,
+                                   _safepoint_id,
                                    initial_running,
                                    _waiting_to_block, iterations);
 
@@ -429,14 +442,14 @@
   // needs cleanup to be completed before running the GC op.
   EventSafepointCleanup cleanup_event;
   do_cleanup_tasks();
-  post_safepoint_cleanup_event(cleanup_event, _safepoint_counter);
+  post_safepoint_cleanup_event(cleanup_event, _safepoint_id);
 
-  post_safepoint_begin_event(begin_event, _safepoint_counter, nof_threads, _current_jni_active_count);
+  post_safepoint_begin_event(begin_event, _safepoint_id, nof_threads, _current_jni_active_count);
   SafepointTracing::cleanup();
 }
 
 void SafepointSynchronize::disarm_safepoint() {
-  uint64_t safepoint_id = _safepoint_counter;
+  uint64_t active_safepoint_counter = _safepoint_counter;
   {
     JavaThreadIteratorWithHandle jtiwh;
 #ifdef ASSERT
@@ -475,7 +488,7 @@
     jtiwh.rewind();
     for (; JavaThread *current = jtiwh.next(); ) {
       // Clear the visited flag to ensure that the critical counts are collected properly.
-      DEBUG_ONLY(current->reset_visited_for_critical_count(safepoint_id);)
+      DEBUG_ONLY(current->reset_visited_for_critical_count(active_safepoint_counter);)
       ThreadSafepointState* cur_state = current->safepoint_state();
       assert(!cur_state->is_running(), "Thread not suspended at safepoint");
       cur_state->restart(); // TSS _running
@@ -497,7 +510,6 @@
 void SafepointSynchronize::end() {
   assert(Threads_lock->owned_by_self(), "must hold Threads_lock");
   EventSafepointEnd event;
-  uint64_t safepoint_id = _safepoint_counter;
   assert(Thread::current()->is_VM_thread(), "Only VM thread can execute a safepoint");
 
   disarm_safepoint();
@@ -506,7 +518,7 @@
 
   SafepointTracing::end();
 
-  post_safepoint_end_event(event, safepoint_id);
+  post_safepoint_end_event(event, safepoint_id());
 }
 
 bool SafepointSynchronize::is_cleanup_needed() {
@@ -554,7 +566,7 @@
     _counters(counters) {}
 
   void work(uint worker_id) {
-    uint64_t safepoint_id = SafepointSynchronize::safepoint_counter();
+    uint64_t safepoint_id = SafepointSynchronize::safepoint_id();
     // All threads deflate monitors and mark nmethods (if necessary).
     Threads::possibly_parallel_threads_do(true, &_cleanup_threads_cl);
 
--- a/src/hotspot/share/runtime/safepoint.hpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/safepoint.hpp	Fri Jun 28 14:36:42 2019 +0530
@@ -48,6 +48,14 @@
 
 class ThreadSafepointState;
 
+class SafepointStateTracker {
+  uint64_t _safepoint_id;
+  bool     _at_safepoint;
+public:
+  SafepointStateTracker(uint64_t safepoint_id, bool at_safepoint);
+  bool safepoint_state_changed();
+};
+
 //
 // Implements roll-forward to safepoint (safepoint synchronization)
 //
@@ -77,6 +85,7 @@
   friend class SafepointMechanism;
   friend class ThreadSafepointState;
   friend class HandshakeState;
+  friend class SafepointStateTracker;
 
   // Threads might read this flag directly, without acquiring the Threads_lock:
   static volatile SynchronizeState _state;
@@ -91,6 +100,11 @@
   // safepoint.
   static volatile uint64_t _safepoint_counter;
 
+  // A change in this counter or a change in the result of
+  // is_at_safepoint() are used by SafepointStateTracker::
+  // safepoint_state_changed() to determine its answer.
+  static uint64_t _safepoint_id;
+
   // JavaThreads that need to block for the safepoint will stop on the
   // _wait_barrier, where they can quickly be started again.
   static WaitBarrier* _wait_barrier;
@@ -114,6 +128,7 @@
   static void disarm_safepoint();
   static void increment_jni_active_count();
   static void decrement_waiting_to_block();
+  static bool thread_not_running(ThreadSafepointState *cur_state);
 
   // Used in safepoint_safe to do a stable load of the thread state.
   static bool try_stable_load_state(JavaThreadState *state,
@@ -127,6 +142,8 @@
   // If true the VMThread may safely process the handshake operation for the JavaThread.
   static bool handshake_safe(JavaThread *thread);
 
+  static uint64_t safepoint_counter()             { return _safepoint_counter; }
+
 public:
 
   static void init(Thread* vmthread);
@@ -141,8 +158,15 @@
   // Query
   static bool is_at_safepoint()                   { return _state == _synchronized; }
   static bool is_synchronizing()                  { return _state == _synchronizing; }
-  static uint64_t safepoint_counter()             { return _safepoint_counter; }
-  static bool is_same_safepoint(uint64_t counter) { return (SafepointSynchronize::safepoint_counter() - counter) < 2; }
+
+  static uint64_t safepoint_id() {
+    return _safepoint_id;
+  }
+
+  static SafepointStateTracker safepoint_state_tracker() {
+    return SafepointStateTracker(safepoint_id(), is_at_safepoint());
+  }
+
   // Exception handling for page polling
   static void handle_polling_page_exception(JavaThread *thread);
 
--- a/src/hotspot/share/runtime/stubRoutines.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/stubRoutines.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "asm/codeBuffer.hpp"
+#include "asm/macroAssembler.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/access.inline.hpp"
 #include "oops/oop.inline.hpp"
--- a/src/hotspot/share/runtime/vmThread.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/runtime/vmThread.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -388,7 +388,7 @@
   // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown.
   // This is because the caller thread could have exited already.
   event->set_caller(is_concurrent ? 0 : JFR_THREAD_ID(op->calling_thread()));
-  event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_counter() : 0);
+  event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0);
   event->commit();
 }
 
--- a/src/hotspot/share/services/diagnosticCommand.cpp	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/hotspot/share/services/diagnosticCommand.cpp	Fri Jun 28 14:36:42 2019 +0530
@@ -129,7 +129,7 @@
 
   // Debug on cmd (only makes sense with JVMTI since the agentlib needs it).
 #if INCLUDE_JVMTI
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DebugOnCmdStartDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DebugOnCmdStartDCmd>(full_export, true, true));
 #endif // INCLUDE_JVMTI
 
 }
--- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -131,8 +131,14 @@
     }
 
     @Override
-    public MethodType resolveConstantDesc(MethodHandles.Lookup lookup) {
-        return MethodType.fromMethodDescriptorString(descriptorString(), lookup.lookupClass().getClassLoader());
+    public MethodType resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
+        MethodType mtype = MethodType.fromMethodDescriptorString(descriptorString(), lookup.lookupClass().getClassLoader());
+        // let's check that the lookup has access to all the types in the method type
+        lookup.accessClass(mtype.returnType());
+        for (Class<?> paramType: mtype.parameterArray()) {
+            lookup.accessClass(paramType);
+        }
+        return mtype;
     }
 
     /**
--- a/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -268,7 +268,7 @@
      *
      * @implSpec
      * The default implementation of this method first checks that the given
-     * socket option {code name} is not null, then throws {@code
+     * socket option {@code name} is not null, then throws {@code
      * UnsupportedOperationException}. Subclasses should override this method
      * with an appropriate implementation.
      *
@@ -296,7 +296,7 @@
      *
      * @implSpec
      * The default implementation of this method first checks that the given
-     * socket option {code name} is not null, then throws {@code
+     * socket option {@code name} is not null, then throws {@code
      * UnsupportedOperationException}. Subclasses should override this method
      * with an appropriate implementation.
      *
--- a/src/java.base/share/classes/java/net/URLStreamHandler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/net/URLStreamHandler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
      *
      * @implSpec
      * The default implementation of this method first checks that the given
-     * {code URL} and {code Proxy} are not null, then throws {@code
+     * {@code URL} and {@code Proxy} are not null, then throws {@code
      * UnsupportedOperationException}. Subclasses should override this method
      * with an appropriate implementation.
      *
--- a/src/java.base/share/classes/java/util/DoubleSummaryStatistics.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/util/DoubleSummaryStatistics.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,6 +59,8 @@
  * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
  * provides the necessary partitioning, isolation, and merging of results for
  * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the count.
  * @since 1.8
  */
 public class DoubleSummaryStatistics implements DoubleConsumer {
--- a/src/java.base/share/classes/java/util/IntSummaryStatistics.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/util/IntSummaryStatistics.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
  * provides the necessary partitioning, isolation, and merging of results for
  * safe and efficient parallel execution.
  *
- * <p>This implementation does not check for overflow of the sum.
+ * <p>This implementation does not check for overflow of the count or the sum.
  * @since 1.8
  */
 public class IntSummaryStatistics implements IntConsumer {
--- a/src/java.base/share/classes/java/util/LongSummaryStatistics.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.base/share/classes/java/util/LongSummaryStatistics.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,7 +60,7 @@
  * provides the necessary partitioning, isolation, and merging of results for
  * safe and efficient parallel execution.
  *
- * <p>This implementation does not check for overflow of the sum.
+ * <p>This implementation does not check for overflow of the count or the sum.
  * @since 1.8
  */
 public class LongSummaryStatistics implements LongConsumer, IntConsumer {
--- a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java	Fri Jun 28 14:36:42 2019 +0530
@@ -97,7 +97,7 @@
     public String getDesktop() {
         String gsi = AccessController.doPrivileged(
                         (PrivilegedAction<String>) ()
-                                -> System.getenv("GNOME_SESSION_ID"));
+                                -> System.getenv("GNOME_DESKTOP_SESSION_ID"));
         return (gsi != null) ? "gnome" : null;
     }
 
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Fri Jun 28 14:36:42 2019 +0530
@@ -195,7 +195,8 @@
             AOTDynamicTypeStore dynoStore = new AOTDynamicTypeStore();
             AOTCompiledClass.setDynamicTypeStore(dynoStore);
 
-            // AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new HotSpotInvokeDynamicPlugin(dynoStore));
+            // AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new
+            // HotSpotInvokeDynamicPlugin(dynoStore));
             // Temporary workaround until JDK-8223533 is fixed.
             // Disable invokedynamic support.
             var indyPlugin = new HotSpotInvokeDynamicPlugin(dynoStore) {
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,6 +25,7 @@
 
 package jdk.tools.jaotc;
 
+import java.util.HashMap;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 
 /**
@@ -56,17 +57,22 @@
     INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
 
     private final int value;
+    private static HashMap<Integer, MarkId> lookup = new HashMap<Integer, MarkId>();
 
+    static {
+        for (MarkId e : values()) {
+            lookup.put(e.value, e);
+        }
+    }
     MarkId(String name) {
         this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name);
     }
 
     static MarkId getEnum(int value) {
-        for (MarkId e : values()) {
-            if (e.value == value) {
-                return e;
-            }
+        MarkId e = lookup.get(value);
+        if (e == null) {
+            throw new InternalError("Unknown enum value: " + value);
         }
-        throw new InternalError("Unknown enum value: " + value);
+        return e;
     }
 }
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MetadataBuilder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,12 +28,12 @@
 import static jdk.tools.jaotc.AOTCompiledClass.getType;
 import static jdk.tools.jaotc.AOTCompiledClass.metadataName;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotGraalServices;
 
 import jdk.tools.jaotc.binformat.BinaryContainer;
 import jdk.tools.jaotc.binformat.ByteContainer;
@@ -82,12 +82,6 @@
         HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
         ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
 
-        Method implicitExceptionsMethod = null;
-        try {
-            implicitExceptionsMethod = HotSpotMetaData.class.getDeclaredMethod("implicitExceptionBytes");
-        } catch (NoSuchMethodException e) {
-        }
-
         // For each of the compiled java methods, create records holding information about them.
         for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
             // Get the current offset in the methodmetadata container.
@@ -104,6 +98,7 @@
             byte[] scopeDesc = metaData.scopesDescBytes();
             byte[] relocationInfo = metaData.relocBytes();
             byte[] oopMapInfo = metaData.oopMaps();
+            byte[] implicitExceptionBytes = HotSpotGraalServices.getImplicitExceptionBytes(metaData);
 
             // create a global symbol at this position for this method
             NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
@@ -148,10 +143,9 @@
                 NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
                 NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
                 NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
-                NativeOrderOutputStream.PatchableInt implictTableOFfset = null;
-
-                if (implicitExceptionsMethod != null) {
-                    implictTableOFfset = metadataStream.patchableInt();
+                NativeOrderOutputStream.PatchableInt implictTableOffset = null;
+                if (implicitExceptionBytes != null) {
+                    implictTableOffset = metadataStream.patchableInt();
                 }
                 NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
                 metadataStream.align(8);
@@ -168,10 +162,9 @@
                 exceptionOffset.set(metadataStream.position());
                 metadataStream.put(metaData.exceptionBytes()).align(8);
 
-                if (implicitExceptionsMethod != null) {
-                    implictTableOFfset.set(metadataStream.position());
-                    byte[] data = (byte[]) implicitExceptionsMethod.invoke(metaData);
-                    metadataStream.put(data).align(8);
+                if (implicitExceptionBytes != null) {
+                    implictTableOffset.set(metadataStream.position());
+                    metadataStream.put(implicitExceptionBytes).align(8);
                 }
 
                 // oopmaps should be last
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java	Fri Jun 28 14:36:42 2019 +0530
@@ -47,7 +47,7 @@
 /**
  * Memory efficient map data structure.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
 
@@ -57,14 +57,14 @@
      *
      * @return the previous value associated with {@code key}, or {@code null} if there was no
      *         mapping for {@code key}.
-     * @since 1.0
+     * @since 19.0
      */
     V put(K key, V value);
 
     /**
      * Copies all of the mappings from {@code other} to this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void putAll(EconomicMap<K, V> other) {
         MapCursor<K, V> e = other.getEntries();
@@ -76,7 +76,7 @@
     /**
      * Copies all of the mappings from {@code other} to this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void putAll(UnmodifiableEconomicMap<? extends K, ? extends V> other) {
         UnmodifiableMapCursor<? extends K, ? extends V> entry = other.getEntries();
@@ -88,7 +88,7 @@
     /**
      * Removes all of the mappings from this map. The map will be empty after this call returns.
      *
-     * @since 1.0
+     * @since 19.0
      */
     void clear();
 
@@ -98,14 +98,14 @@
      *
      * @return the previous value associated with {@code key}, or {@code null} if there was no
      *         mapping for {@code key}.
-     * @since 1.0
+     * @since 19.0
      */
     V removeKey(K key);
 
     /**
      * Returns a {@link MapCursor} view of the mappings contained in this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     MapCursor<K, V> getEntries();
@@ -115,7 +115,7 @@
      * all entries have been processed or the function throws an exception. Exceptions thrown by the
      * function are relayed to the caller.
      *
-     * @since 1.0
+     * @since 19.0
      */
     void replaceAll(BiFunction<? super K, ? super V, ? extends V> function);
 
@@ -123,7 +123,7 @@
      * Creates a new map that guarantees insertion order on the key set with the default
      * {@link Equivalence#DEFAULT} comparison strategy for keys.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create() {
         return EconomicMap.create(Equivalence.DEFAULT);
@@ -134,7 +134,7 @@
      * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified
      * capacity.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create(int initialCapacity) {
         return EconomicMap.create(Equivalence.DEFAULT, initialCapacity);
@@ -144,7 +144,7 @@
      * Creates a new map that guarantees insertion order on the key set with the given comparison
      * strategy for keys.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create(Equivalence strategy) {
         return EconomicMapImpl.create(strategy, false);
@@ -155,7 +155,7 @@
      * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the
      * specified existing map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create(UnmodifiableEconomicMap<K, V> m) {
         return EconomicMap.create(Equivalence.DEFAULT, m);
@@ -165,7 +165,7 @@
      * Creates a new map that guarantees insertion order on the key set and copies all elements from
      * the specified existing map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> m) {
         return EconomicMapImpl.create(strategy, m, false);
@@ -175,7 +175,7 @@
      * Creates a new map that guarantees insertion order on the key set and initializes with a
      * specified capacity.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> create(Equivalence strategy, int initialCapacity) {
         return EconomicMapImpl.create(strategy, initialCapacity, false);
@@ -184,7 +184,7 @@
     /**
      * Wraps an existing {@link Map} as an {@link EconomicMap}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <K, V> EconomicMap<K, V> wrapMap(Map<K, V> map) {
         return new EconomicMap<K, V>() {
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java	Fri Jun 28 14:36:42 2019 +0530
@@ -45,7 +45,7 @@
 /**
  * Memory efficient set data structure.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface EconomicSet<E> extends UnmodifiableEconomicSet<E> {
 
@@ -53,7 +53,7 @@
      * Adds {@code element} to this set if it is not already present.
      *
      * @return {@code true} if this set did not already contain {@code element}.
-     * @since 1.0
+     * @since 19.0
      */
     boolean add(E element);
 
@@ -61,21 +61,21 @@
      * Removes {@code element} from this set if it is present. This set will not contain
      * {@code element} once the call returns.
      *
-     * @since 1.0
+     * @since 19.0
      */
     void remove(E element);
 
     /**
      * Removes all of the elements from this set. The set will be empty after this call returns.
      *
-     * @since 1.0
+     * @since 19.0
      */
     void clear();
 
     /**
      * Adds all of the elements in {@code other} to this set if they're not already present.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void addAll(EconomicSet<E> other) {
         addAll(other.iterator());
@@ -84,7 +84,7 @@
     /**
      * Adds all of the elements in {@code values} to this set if they're not already present.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void addAll(Iterable<E> values) {
         addAll(values.iterator());
@@ -94,7 +94,7 @@
      * Adds all of the elements enumerated by {@code iterator} to this set if they're not already
      * present.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void addAll(Iterator<E> iterator) {
         while (iterator.hasNext()) {
@@ -105,7 +105,7 @@
     /**
      * Removes from this set all of its elements that are contained in {@code other}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void removeAll(EconomicSet<E> other) {
         removeAll(other.iterator());
@@ -114,7 +114,7 @@
     /**
      * Removes from this set all of its elements that are contained in {@code values}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void removeAll(Iterable<E> values) {
         removeAll(values.iterator());
@@ -123,7 +123,7 @@
     /**
      * Removes from this set all of its elements that are enumerated by {@code iterator}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void removeAll(Iterator<E> iterator) {
         while (iterator.hasNext()) {
@@ -134,7 +134,7 @@
     /**
      * Removes from this set all of its elements that are not contained in {@code other}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default void retainAll(EconomicSet<E> other) {
         Iterator<E> iterator = iterator();
@@ -150,7 +150,7 @@
      * Creates a new set guaranteeing insertion order when iterating over its elements with the
      * default {@link Equivalence#DEFAULT} comparison strategy.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create() {
         return EconomicSet.create(Equivalence.DEFAULT);
@@ -159,7 +159,7 @@
     /**
      * Creates a new set guaranteeing insertion order when iterating over its elements.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create(Equivalence strategy) {
         return EconomicMapImpl.create(strategy, true);
@@ -170,7 +170,7 @@
      * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
      * specified collection.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create(int initialCapacity) {
         return EconomicSet.create(Equivalence.DEFAULT, initialCapacity);
@@ -181,7 +181,7 @@
      * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
      * specified collection.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create(UnmodifiableEconomicSet<E> c) {
         return EconomicSet.create(Equivalence.DEFAULT, c);
@@ -191,7 +191,7 @@
      * Creates a new set guaranteeing insertion order when iterating over its elements and
      * initializes with the given capacity.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create(Equivalence strategy, int initialCapacity) {
         return EconomicMapImpl.create(strategy, initialCapacity, true);
@@ -201,7 +201,7 @@
      * Creates a new set guaranteeing insertion order when iterating over its elements and inserts
      * all elements of the specified collection.
      *
-     * @since 1.0
+     * @since 19.0
      */
     static <E> EconomicSet<E> create(Equivalence strategy, UnmodifiableEconomicSet<E> c) {
         return EconomicMapImpl.create(strategy, c, true);
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,7 +44,7 @@
  * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT},
  * {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}.
  *
- * @since 1.0
+ * @since 19.0
  */
 public abstract class Equivalence {
 
@@ -53,7 +53,7 @@
      * for obtaining hash values. Do not change the logic of this class as it may be inlined in
      * other places.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static final Equivalence DEFAULT = new Equivalence() {
 
@@ -72,7 +72,7 @@
      * Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining
      * hash values. Do not change the logic of this class as it may be inlined in other places.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static final Equivalence IDENTITY = new Equivalence() {
 
@@ -92,7 +92,7 @@
      * {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of
      * this class as it may be inlined in other places.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() {
 
@@ -110,7 +110,7 @@
     /**
      * Subclass for creating custom equivalence definitions.
      *
-     * @since 1.0
+     * @since 19.0
      */
     protected Equivalence() {
     }
@@ -119,14 +119,14 @@
      * Returns {@code true} if the non-{@code null} arguments are equal to each other and
      * {@code false} otherwise.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public abstract boolean equals(Object a, Object b);
 
     /**
      * Returns the hash code of a non-{@code null} argument {@code o}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public abstract int hashCode(Object o);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 /**
  * Cursor to iterate over a mutable map.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface MapCursor<K, V> extends UnmodifiableMapCursor<K, V> {
     /**
@@ -51,7 +51,7 @@
      * {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on
      * the current entry.
      *
-     * @since 1.0
+     * @since 19.0
      */
     void remove();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java	Fri Jun 28 14:36:42 2019 +0530
@@ -45,7 +45,7 @@
 /**
  * Utility class representing a pair of values.
  *
- * @since 1.0
+ * @since 19.0
  */
 public final class Pair<L, R> {
 
@@ -57,7 +57,7 @@
     /**
      * Returns an empty pair.
      *
-     * @since 1.0
+     * @since 19.0
      */
     @SuppressWarnings("unchecked")
     public static <L, R> Pair<L, R> empty() {
@@ -69,7 +69,7 @@
      * {@code left} is null.
      *
      * @return the constructed pair or an empty pair if {@code left} is null.
-     * @since 1.0
+     * @since 19.0
      */
     public static <L, R> Pair<L, R> createLeft(L left) {
         if (left == null) {
@@ -84,7 +84,7 @@
      * {@code right} is null.
      *
      * @return the constructed pair or an empty pair if {@code right} is null.
-     * @since 1.0
+     * @since 19.0
      */
     public static <L, R> Pair<L, R> createRight(R right) {
         if (right == null) {
@@ -99,7 +99,7 @@
      * {@code right}, or returns an empty pair if both inputs are null.
      *
      * @return the constructed pair or an empty pair if both inputs are null.
-     * @since 1.0
+     * @since 19.0
      */
     public static <L, R> Pair<L, R> create(L left, R right) {
         if (right == null && left == null) {
@@ -117,7 +117,7 @@
     /**
      * Returns the left value of this pair.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public L getLeft() {
         return left;
@@ -126,7 +126,7 @@
     /**
      * Returns the right value of this pair.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public R getRight() {
         return right;
@@ -135,7 +135,7 @@
     /**
      * {@inheritDoc}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     public int hashCode() {
@@ -145,7 +145,7 @@
     /**
      * {@inheritDoc}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @SuppressWarnings("unchecked")
     @Override
@@ -165,7 +165,7 @@
     /**
      * {@inheritDoc}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     public String toString() {
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 /**
  * Unmodifiable memory efficient map data structure.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface UnmodifiableEconomicMap<K, V> {
 
@@ -51,7 +51,7 @@
      * Returns the value to which {@code key} is mapped, or {@code null} if this map contains no
      * mapping for {@code key}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     V get(K key);
 
@@ -59,7 +59,7 @@
      * Returns the value to which {@code key} is mapped, or {@code defaultValue} if this map
      * contains no mapping for {@code key}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     default V get(K key, V defaultValue) {
         V v = get(key);
@@ -72,42 +72,42 @@
     /**
      * Returns {@code true} if this map contains a mapping for {@code key}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean containsKey(K key);
 
     /**
      * Returns the number of key-value mappings in this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     int size();
 
     /**
      * Returns {@code true} if this map contains no key-value mappings.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean isEmpty();
 
     /**
      * Returns a {@link Iterable} view of the values contained in this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Iterable<V> getValues();
 
     /**
      * Returns a {@link Iterable} view of the keys contained in this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Iterable<K> getKeys();
 
     /**
      * Returns a {@link UnmodifiableMapCursor} view of the mappings contained in this map.
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnmodifiableMapCursor<K, V> getEntries();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,28 +43,28 @@
 /**
  * Unmodifiable memory efficient set data structure.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface UnmodifiableEconomicSet<E> extends Iterable<E> {
 
     /**
      * Returns {@code true} if this set contains a mapping for the {@code element}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean contains(E element);
 
     /**
      * Returns the number of elements in this set.
      *
-     * @since 1.0
+     * @since 19.0
      */
     int size();
 
     /**
      * Returns {@code true} if this set contains no elements.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean isEmpty();
 
@@ -76,7 +76,7 @@
      * @return an array containing all the elements in this set.
      * @throws UnsupportedOperationException if the length of {@code target} does not equal the size
      *             of this set.
-     * @since 1.0
+     * @since 19.0
      */
     default E[] toArray(E[] target) {
         if (target.length != size()) {
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,28 +43,28 @@
 /**
  * Cursor to iterate over a map without changing its contents.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface UnmodifiableMapCursor<K, V> {
     /**
      * Advances to the next entry.
      *
      * @return {@code true} if a next entry exists, {@code false} if there is no next entry.
-     * @since 1.0
+     * @since 19.0
      */
     boolean advance();
 
     /**
      * The key of the current entry.
      *
-     * @since 1.0
+     * @since 19.0
      */
     K getKey();
 
     /**
      * The value of the current entry.
      *
-     * @since 1.0
+     * @since 19.0
      */
     V getValue();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,7 @@
  * @see jdk.internal.vm.compiler.collections.EconomicMap
  * @see jdk.internal.vm.compiler.collections.EconomicSet
  *
- * @since 1.0
+ * @since 19.0
  */
 
 
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal/LibGraal.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal/LibGraal.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,67 +33,43 @@
 public class LibGraal {
 
     public static boolean isAvailable() {
-        return isCurrentRuntime() || libgraalIsolate != 0L;
+        return inLibGraal() || isolate != 0L;
     }
 
-    public static boolean isCurrentRuntime() {
+    public static boolean inLibGraal() {
         return Services.IS_IN_NATIVE_IMAGE;
     }
 
-    public static long getIsolate() {
-        if (isCurrentRuntime() || !isAvailable()) {
-            throw new IllegalStateException();
-        }
-        return libgraalIsolate;
-    }
-
-    public static long getIsolateThread() {
-        if (isCurrentRuntime()) {
-            throw new IllegalStateException();
-        }
-        return CURRENT_ISOLATE_THREAD.get();
-    }
-
-    @SuppressWarnings("unused")
-    public static long[] registerNativeMethods(HotSpotJVMCIRuntime runtime, Class<?> clazz) {
+    public static void registerNativeMethods(HotSpotJVMCIRuntime runtime, Class<?> clazz) {
         if (clazz.isPrimitive()) {
             throw new IllegalArgumentException();
         }
-        if (isCurrentRuntime() || !isAvailable()) {
+        if (inLibGraal() || !isAvailable()) {
             throw new IllegalStateException();
         }
-        // Waiting for https://bugs.openjdk.java.net/browse/JDK-8220623
-        // return runtime.registerNativeMethods(clazz);
-        throw new IllegalStateException("Requires JDK-8220623");
+        runtime.registerNativeMethods(clazz);
     }
 
-    @SuppressWarnings("unused")
     public static long translate(HotSpotJVMCIRuntime runtime, Object obj) {
         if (!isAvailable()) {
             throw new IllegalStateException();
         }
-        // return runtime.translate(obj);
-        throw new IllegalStateException("Requires JDK-8220623");
+        if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
+            throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
+        }
+        return runtime.translate(obj);
     }
 
-    @SuppressWarnings("unused")
     public static <T> T unhand(HotSpotJVMCIRuntime runtime, Class<T> type, long handle) {
         if (!isAvailable()) {
             throw new IllegalStateException();
         }
-        // return runtime.unhand(type, handle);
-        throw new IllegalStateException("Requires JDK-8220623");
+        if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
+            throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
+        }
+        return runtime.unhand(type, handle);
     }
 
-    private static final ThreadLocal<Long> CURRENT_ISOLATE_THREAD = new ThreadLocal<>() {
-        @Override
-        protected Long initialValue() {
-            return attachThread(libgraalIsolate);
-        }
-    };
-
-    private static final long libgraalIsolate = Services.IS_BUILDING_NATIVE_IMAGE ? 0L : initializeLibgraal();
-
     private static long initializeLibgraal() {
         try {
             // Initialize JVMCI to ensure JVMCI opens its packages to
@@ -101,20 +77,27 @@
             // below will fail on JDK13+.
             Services.initializeJVMCI();
 
-            // Waiting for https://bugs.openjdk.java.net/browse/JDK-8220623
-            // HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
-            // long[] nativeInterface = runtime.registerNativeMethods(LibGraal.class);
-            // return nativeInterface[1];
-            return 0L;
+            HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
+            long[] nativeInterface = runtime.registerNativeMethods(LibGraal.class);
+            return nativeInterface[1];
         } catch (UnsupportedOperationException e) {
             return 0L;
         }
     }
 
-    /**
-     * Attaches the current thread to a thread in {@code isolate}.
-     *
-     * @param isolate
-     */
-    private static native long attachThread(long isolate);
+    static final long isolate = Services.IS_BUILDING_NATIVE_IMAGE ? 0L : initializeLibgraal();
+
+    static boolean isCurrentThreadAttached(HotSpotJVMCIRuntime runtime) {
+        return runtime.isCurrentThreadAttached();
+    }
+
+    static boolean attachCurrentThread(HotSpotJVMCIRuntime runtime) {
+        return runtime.attachCurrentThread(false);
+    }
+
+    static void detachCurrentThread(HotSpotJVMCIRuntime runtime) {
+        runtime.detachCurrentThread();
+    }
+
+    static native long getCurrentIsolateThread(long iso);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal/LibGraalScope.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package jdk.internal.vm.compiler.libgraal;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+
+/**
+ * Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope(HotSpotJVMCIRuntime)
+ * Opening} a scope attaches the current thread to libgraal and {@linkplain #close() closing} it
+ * detaches the current thread.
+ */
+public final class LibGraalScope implements AutoCloseable {
+
+    static final ThreadLocal<LibGraalScope> currentScope = new ThreadLocal<>();
+
+    private final LibGraalScope parent;
+    private final boolean topLevel;
+    private final HotSpotJVMCIRuntime runtime;
+    private final long isolateThread;
+
+    /**
+     * Gets the isolate thread associated with the current thread. The current thread must be in an
+     * {@linkplain #LibGraalScope(HotSpotJVMCIRuntime) opened} scope.
+     *
+     * @returns a value that can be used for the IsolateThreadContext argument of a {@code native}
+     *          method {@link LibGraal#registerNativeMethods linked} to a CEntryPoint function in
+     *          libgraal
+     * @throws IllegalStateException if not the current thread is not attached to libgraal
+     */
+    public static long getIsolateThread() {
+        LibGraalScope scope = currentScope.get();
+        if (scope == null) {
+            throw new IllegalStateException("Cannot get isolate thread outside of a " + LibGraalScope.class.getSimpleName());
+        }
+        return scope.isolateThread;
+    }
+
+    /**
+     * Enters a scope for making calls into libgraal. If there is no existing libgraal scope for the
+     * current thread, the current thread is attached to libgraal. When the outer most scope is
+     * closed, the current thread is detached from libgraal.
+     *
+     * This must be used in a try-with-resources statement.
+     *
+     * This cannot be called from {@linkplain LibGraal#inLibGraal() within} libgraal.
+     *
+     * @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
+     *             or {@link LibGraal#inLibGraal()} returns true
+     */
+    public LibGraalScope(HotSpotJVMCIRuntime runtime) {
+        if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
+            throw new IllegalStateException();
+        }
+        this.runtime = runtime;
+        parent = currentScope.get();
+        boolean top = false;
+        if (parent == null) {
+            top = LibGraal.attachCurrentThread(runtime);
+            isolateThread = LibGraal.getCurrentIsolateThread(LibGraal.isolate);
+        } else {
+            isolateThread = parent.isolateThread;
+        }
+        topLevel = top;
+        currentScope.set(this);
+    }
+
+    @Override
+    public void close() {
+        if (topLevel) {
+            LibGraal.detachCurrentThread(runtime);
+        }
+        currentScope.set(parent);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal/OptionsEncoder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal/OptionsEncoder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -162,6 +162,9 @@
                 }
                 res.put(key, value);
             }
+            if (in.available() != 0) {
+                throw new IllegalArgumentException(in.available() + " undecoded bytes");
+            }
         } catch (IOException ioe) {
             throw new IllegalArgumentException(ioe);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 /**
  * A machine-word-sized value that can be compared for equality.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface ComparableWord extends WordBase {
 
@@ -53,7 +53,7 @@
      * @param val value to which this word is to be compared.
      * @return {@code this == val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean equal(ComparableWord val);
 
@@ -63,7 +63,7 @@
      * @param val value to which this word is to be compared.
      * @return {@code this != val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean notEqual(ComparableWord val);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java	Fri Jun 28 14:36:42 2019 +0530
@@ -50,7 +50,7 @@
  * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
  * {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
  *
- * @since 1.0
+ * @since 19.0
  */
 public abstract class LocationIdentity {
 
@@ -82,7 +82,7 @@
      * Creates a new location identity. Subclasses are responsible to provide proper implementations
      * of {@link #equals} and {@link #hashCode}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     protected LocationIdentity() {
     }
@@ -92,7 +92,7 @@
      * such a location kill all reads from mutable locations and a read from this location is killed
      * by any write (except for initialization writes).
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
 
@@ -101,7 +101,7 @@
      * is written. Kills no read. The previous value at the given location must be either
      * uninitialized or null. Writes to this location do not need a GC pre-barrier.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
 
@@ -110,7 +110,7 @@
      * such a location kill all reads from mutable locations and a read from this location is killed
      * by any write (except for initialization writes).
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static LocationIdentity any() {
         return ANY_LOCATION;
@@ -121,7 +121,7 @@
      * is written. Kills no read. The previous value at the given location must be either
      * uninitialized or null. Writes to this location do not need a GC pre-barrier.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public static LocationIdentity init() {
         return INIT_LOCATION;
@@ -131,14 +131,14 @@
      * Denotes a location is unchanging in all cases. Not that this is different than the Java
      * notion of final which only requires definite assignment.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public abstract boolean isImmutable();
 
     /**
      * The inversion of {@link #isImmutable}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public final boolean isMutable() {
         return !isImmutable();
@@ -147,7 +147,7 @@
     /**
      * Returns true if this location identity is {@link #any}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public final boolean isAny() {
         return this == ANY_LOCATION;
@@ -156,7 +156,7 @@
     /**
      * Returns true if this location identity is {@link #init}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public final boolean isInit() {
         return this == INIT_LOCATION;
@@ -165,7 +165,7 @@
     /**
      * Returns true if this location identity is not {@link #any}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public final boolean isSingle() {
         return this != ANY_LOCATION;
@@ -175,7 +175,7 @@
      * Returns true if the memory slice denoted by this location identity may overlap with the
      * provided other location identity.
      *
-     * @since 1.0
+     * @since 19.0
      */
     public final boolean overlaps(LocationIdentity other) {
         return isAny() || other.isAny() || this.equals(other);
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java	Fri Jun 28 14:36:42 2019 +0530
@@ -47,7 +47,7 @@
  * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject
  * and writeObject methods access uncompressed pointers.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface Pointer extends UnsignedWord, PointerBase {
 
@@ -58,7 +58,7 @@
      *
      * @return this Pointer cast to Object.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object toObject();
 
@@ -69,7 +69,7 @@
      *
      * @return this Pointer cast to non-null Object.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object toObjectNonNull();
 
@@ -85,7 +85,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     byte readByte(WordBase offset, LocationIdentity locationIdentity);
 
@@ -101,7 +101,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     char readChar(WordBase offset, LocationIdentity locationIdentity);
 
@@ -117,7 +117,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     short readShort(WordBase offset, LocationIdentity locationIdentity);
 
@@ -133,7 +133,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     int readInt(WordBase offset, LocationIdentity locationIdentity);
 
@@ -149,7 +149,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     long readLong(WordBase offset, LocationIdentity locationIdentity);
 
@@ -165,7 +165,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     float readFloat(WordBase offset, LocationIdentity locationIdentity);
 
@@ -181,7 +181,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     double readDouble(WordBase offset, LocationIdentity locationIdentity);
 
@@ -197,7 +197,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T readWord(WordBase offset, LocationIdentity locationIdentity);
 
@@ -213,7 +213,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object readObject(WordBase offset, LocationIdentity locationIdentity);
 
@@ -225,7 +225,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     byte readByte(int offset, LocationIdentity locationIdentity);
 
@@ -237,7 +237,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     char readChar(int offset, LocationIdentity locationIdentity);
 
@@ -249,7 +249,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     short readShort(int offset, LocationIdentity locationIdentity);
 
@@ -261,7 +261,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     int readInt(int offset, LocationIdentity locationIdentity);
 
@@ -273,7 +273,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     long readLong(int offset, LocationIdentity locationIdentity);
 
@@ -285,7 +285,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     float readFloat(int offset, LocationIdentity locationIdentity);
 
@@ -297,7 +297,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     double readDouble(int offset, LocationIdentity locationIdentity);
 
@@ -309,7 +309,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T readWord(int offset, LocationIdentity locationIdentity);
 
@@ -321,7 +321,7 @@
      * @param locationIdentity the identity of the read
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object readObject(int offset, LocationIdentity locationIdentity);
 
@@ -337,7 +337,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
 
@@ -353,7 +353,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
 
@@ -369,7 +369,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
 
@@ -385,7 +385,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
 
@@ -401,7 +401,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
 
@@ -417,7 +417,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
 
@@ -433,7 +433,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
 
@@ -449,7 +449,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
 
@@ -465,7 +465,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity);
 
@@ -481,7 +481,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
 
@@ -493,7 +493,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeByte(int offset, byte val, LocationIdentity locationIdentity);
 
@@ -505,7 +505,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeChar(int offset, char val, LocationIdentity locationIdentity);
 
@@ -517,7 +517,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeShort(int offset, short val, LocationIdentity locationIdentity);
 
@@ -529,7 +529,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeInt(int offset, int val, LocationIdentity locationIdentity);
 
@@ -541,7 +541,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeLong(int offset, long val, LocationIdentity locationIdentity);
 
@@ -553,7 +553,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeFloat(int offset, float val, LocationIdentity locationIdentity);
 
@@ -565,7 +565,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeDouble(int offset, double val, LocationIdentity locationIdentity);
 
@@ -577,7 +577,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
 
@@ -589,7 +589,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void initializeLong(int offset, long val, LocationIdentity locationIdentity);
 
@@ -601,7 +601,7 @@
      * @param locationIdentity the identity of the write
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeObject(int offset, Object val, LocationIdentity locationIdentity);
 
@@ -616,7 +616,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     byte readByte(WordBase offset);
 
@@ -631,7 +631,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     char readChar(WordBase offset);
 
@@ -646,7 +646,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     short readShort(WordBase offset);
 
@@ -661,7 +661,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     int readInt(WordBase offset);
 
@@ -676,7 +676,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     long readLong(WordBase offset);
 
@@ -691,7 +691,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     float readFloat(WordBase offset);
 
@@ -706,7 +706,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     double readDouble(WordBase offset);
 
@@ -721,7 +721,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T readWord(WordBase offset);
 
@@ -736,7 +736,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object readObject(WordBase offset);
 
@@ -747,7 +747,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     byte readByte(int offset);
 
@@ -758,7 +758,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     char readChar(int offset);
 
@@ -769,7 +769,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     short readShort(int offset);
 
@@ -780,7 +780,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     int readInt(int offset);
 
@@ -791,7 +791,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     long readLong(int offset);
 
@@ -802,7 +802,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     float readFloat(int offset);
 
@@ -813,7 +813,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     double readDouble(int offset);
 
@@ -824,7 +824,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T readWord(int offset);
 
@@ -835,7 +835,7 @@
      * @param offset the signed offset for the memory access
      * @return the result of the memory access
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object readObject(int offset);
 
@@ -850,7 +850,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeByte(WordBase offset, byte val);
 
@@ -865,7 +865,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeChar(WordBase offset, char val);
 
@@ -880,7 +880,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeShort(WordBase offset, short val);
 
@@ -895,7 +895,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeInt(WordBase offset, int val);
 
@@ -910,7 +910,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeLong(WordBase offset, long val);
 
@@ -925,7 +925,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeFloat(WordBase offset, float val);
 
@@ -940,7 +940,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeDouble(WordBase offset, double val);
 
@@ -955,7 +955,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeWord(WordBase offset, WordBase val);
 
@@ -970,7 +970,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeObject(WordBase offset, Object val);
 
@@ -990,7 +990,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     int compareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
 
@@ -1010,7 +1010,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     long compareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
 
@@ -1030,7 +1030,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T compareAndSwapWord(WordBase offset, T expectedValue, T newValue, LocationIdentity locationIdentity);
 
@@ -1050,7 +1050,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object compareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
 
@@ -1070,7 +1070,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
 
@@ -1090,7 +1090,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
 
@@ -1110,7 +1110,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
 
@@ -1130,7 +1130,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
 
@@ -1141,7 +1141,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeByte(int offset, byte val);
 
@@ -1152,7 +1152,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeChar(int offset, char val);
 
@@ -1163,7 +1163,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeShort(int offset, short val);
 
@@ -1174,7 +1174,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeInt(int offset, int val);
 
@@ -1185,7 +1185,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeLong(int offset, long val);
 
@@ -1196,7 +1196,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeFloat(int offset, float val);
 
@@ -1207,7 +1207,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeDouble(int offset, double val);
 
@@ -1218,7 +1218,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeWord(int offset, WordBase val);
 
@@ -1229,7 +1229,7 @@
      * @param offset the signed offset for the memory access
      * @param val the value to be written to memory
      *
-     * @since 1.0
+     * @since 19.0
      */
     void writeObject(int offset, Object val);
 
@@ -1245,7 +1245,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
 
@@ -1261,7 +1261,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
 
@@ -1277,7 +1277,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     <T extends WordBase> T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity);
 
@@ -1293,7 +1293,7 @@
      * @return The value that was read for comparison, which is {@code expectedValue} if the
      *         exchange was performed.
      *
-     * @since 1.0
+     * @since 19.0
      */
     Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
 
@@ -1309,7 +1309,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
 
@@ -1325,7 +1325,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
 
@@ -1341,7 +1341,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
 
@@ -1357,7 +1357,7 @@
      * @return {@code true} if successful. False return indicates that the actual value was not
      *         equal to the expected value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean logicCompareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
 
@@ -1371,7 +1371,7 @@
      * @param val value to be added to this Pointer.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer add(UnsignedWord val);
@@ -1382,7 +1382,7 @@
      * @param val value to be added to this Pointer.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer add(int val);
@@ -1393,7 +1393,7 @@
      * @param val value to be subtracted from this Pointer.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer subtract(UnsignedWord val);
@@ -1404,7 +1404,7 @@
      * @param val value to be subtracted from this Pointer.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer subtract(int val);
@@ -1415,7 +1415,7 @@
      * @param val value to be AND'ed with this Pointer.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer and(UnsignedWord val);
@@ -1426,7 +1426,7 @@
      * @param val value to be AND'ed with this Pointer.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer and(int val);
@@ -1437,7 +1437,7 @@
      * @param val value to be OR'ed with this Pointer.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer or(UnsignedWord val);
@@ -1448,7 +1448,7 @@
      * @param val value to be OR'ed with this Pointer.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     Pointer or(int val);
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,21 +44,21 @@
  * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
  * necessarily all the memory access methods defined in {@link Pointer}).
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface PointerBase extends ComparableWord {
 
     /**
      * Returns true if this pointer is the {@link WordFactory#nullPointer null pointer}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean isNull();
 
     /**
      * Returns true if this pointer is not the {@link WordFactory#nullPointer null pointer}.
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean isNonNull();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 /**
  * Represents a signed word-sized value.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface SignedWord extends ComparableWord {
 
@@ -53,7 +53,7 @@
      * @param val value to be added to this Signed.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord add(SignedWord val);
 
@@ -63,7 +63,7 @@
      * @param val value to be subtracted from this Signed.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord subtract(SignedWord val);
 
@@ -73,7 +73,7 @@
      * @param val value to be multiplied by this Signed.
      * @return {@code this * val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord multiply(SignedWord val);
 
@@ -83,7 +83,7 @@
      * @param val value by which this Signed is to be divided.
      * @return {@code this / val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedDivide(SignedWord val);
 
@@ -93,7 +93,7 @@
      * @param val value by which this Signed is to be divided, and the remainder computed.
      * @return {@code this % val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedRemainder(SignedWord val);
 
@@ -103,7 +103,7 @@
      * @param n shift distance, in bits.
      * @return {@code this << n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord shiftLeft(UnsignedWord n);
 
@@ -113,7 +113,7 @@
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedShiftRight(UnsignedWord n);
 
@@ -124,7 +124,7 @@
      * @param val value to be AND'ed with this Signed.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord and(SignedWord val);
 
@@ -135,7 +135,7 @@
      * @param val value to be OR'ed with this Signed.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord or(SignedWord val);
 
@@ -146,7 +146,7 @@
      * @param val value to be XOR'ed with this Signed.
      * @return {@code this ^ val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord xor(SignedWord val);
 
@@ -156,7 +156,7 @@
      *
      * @return {@code ~this}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord not();
 
@@ -166,7 +166,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this == val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean equal(SignedWord val);
 
@@ -176,7 +176,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this != val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean notEqual(SignedWord val);
 
@@ -186,7 +186,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this < val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean lessThan(SignedWord val);
 
@@ -196,7 +196,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this <= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean lessOrEqual(SignedWord val);
 
@@ -206,7 +206,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this > val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean greaterThan(SignedWord val);
 
@@ -216,7 +216,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this >= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean greaterOrEqual(SignedWord val);
 
@@ -226,7 +226,7 @@
      * @param val value to be added to this Signed.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord add(int val);
 
@@ -236,7 +236,7 @@
      * @param val value to be subtracted from this Signed.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord subtract(int val);
 
@@ -246,7 +246,7 @@
      * @param val value to be multiplied by this Signed.
      * @return {@code this * val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord multiply(int val);
 
@@ -256,7 +256,7 @@
      * @param val value by which this Signed is to be divided.
      * @return {@code this / val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedDivide(int val);
 
@@ -266,7 +266,7 @@
      * @param val value by which this Signed is to be divided, and the remainder computed.
      * @return {@code this % val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedRemainder(int val);
 
@@ -276,7 +276,7 @@
      * @param n shift distance, in bits.
      * @return {@code this << n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord shiftLeft(int n);
 
@@ -286,7 +286,7 @@
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord signedShiftRight(int n);
 
@@ -297,7 +297,7 @@
      * @param val value to be AND'ed with this Signed.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord and(int val);
 
@@ -308,7 +308,7 @@
      * @param val value to be OR'ed with this Signed.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord or(int val);
 
@@ -319,7 +319,7 @@
      * @param val value to be XOR'ed with this Signed.
      * @return {@code this ^ val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     SignedWord xor(int val);
 
@@ -329,7 +329,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this == val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean equal(int val);
 
@@ -339,7 +339,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this != val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean notEqual(int val);
 
@@ -349,7 +349,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this < val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean lessThan(int val);
 
@@ -359,7 +359,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this <= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean lessOrEqual(int val);
 
@@ -369,7 +369,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this > val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean greaterThan(int val);
 
@@ -379,7 +379,7 @@
      * @param val value to which this Signed is to be compared.
      * @return {@code this >= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean greaterOrEqual(int val);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 /**
  * Represents an unsigned word-sized value.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface UnsignedWord extends ComparableWord {
 
@@ -53,7 +53,7 @@
      * @param val value to be added to this Unsigned.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord add(UnsignedWord val);
 
@@ -63,7 +63,7 @@
      * @param val value to be subtracted from this Unsigned.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord subtract(UnsignedWord val);
 
@@ -73,7 +73,7 @@
      * @param val value to be multiplied by this Unsigned.
      * @return {@code this * val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord multiply(UnsignedWord val);
 
@@ -83,7 +83,7 @@
      * @param val value by which this Unsigned is to be divided.
      * @return {@code this / val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedDivide(UnsignedWord val);
 
@@ -93,7 +93,7 @@
      * @param val value by which this Unsigned is to be divided, and the remainder computed.
      * @return {@code this % val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedRemainder(UnsignedWord val);
 
@@ -103,7 +103,7 @@
      * @param n shift distance, in bits.
      * @return {@code this << n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord shiftLeft(UnsignedWord n);
 
@@ -113,7 +113,7 @@
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedShiftRight(UnsignedWord n);
 
@@ -123,7 +123,7 @@
      * @param val value to be AND'ed with this Unsigned.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord and(UnsignedWord val);
 
@@ -133,7 +133,7 @@
      * @param val value to be OR'ed with this Unsigned.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord or(UnsignedWord val);
 
@@ -143,7 +143,7 @@
      * @param val value to be XOR'ed with this Unsigned.
      * @return {@code this ^ val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord xor(UnsignedWord val);
 
@@ -152,7 +152,7 @@
      *
      * @return {@code ~this}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord not();
 
@@ -162,7 +162,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this == val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean equal(UnsignedWord val);
 
@@ -172,7 +172,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this != val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean notEqual(UnsignedWord val);
 
@@ -182,7 +182,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this < val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean belowThan(UnsignedWord val);
 
@@ -192,7 +192,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this <= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean belowOrEqual(UnsignedWord val);
 
@@ -202,7 +202,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this > val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean aboveThan(UnsignedWord val);
 
@@ -212,7 +212,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this >= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean aboveOrEqual(UnsignedWord val);
 
@@ -225,7 +225,7 @@
      * @param val value to be added to this Unsigned.
      * @return {@code this + val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord add(int val);
 
@@ -238,7 +238,7 @@
      * @param val value to be subtracted from this Unsigned.
      * @return {@code this - val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord subtract(int val);
 
@@ -251,7 +251,7 @@
      * @param val value to be multiplied by this Unsigned.
      * @return {@code this * val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord multiply(int val);
 
@@ -264,7 +264,7 @@
      * @param val value by which this Unsigned is to be divided.
      * @return {@code this / val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedDivide(int val);
 
@@ -277,7 +277,7 @@
      * @param val value by which this Unsigned is to be divided, and the remainder computed.
      * @return {@code this % val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedRemainder(int val);
 
@@ -290,7 +290,7 @@
      * @param n shift distance, in bits.
      * @return {@code this << n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord shiftLeft(int n);
 
@@ -303,7 +303,7 @@
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord unsignedShiftRight(int n);
 
@@ -316,7 +316,7 @@
      * @param val value to be AND'ed with this Unsigned.
      * @return {@code this & val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord and(int val);
 
@@ -329,7 +329,7 @@
      * @param val value to be OR'ed with this Unsigned.
      * @return {@code this | val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord or(int val);
 
@@ -342,7 +342,7 @@
      * @param val value to be XOR'ed with this Unsigned.
      * @return {@code this ^ val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     UnsignedWord xor(int val);
 
@@ -355,7 +355,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this == val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean equal(int val);
 
@@ -368,7 +368,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this != val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean notEqual(int val);
 
@@ -381,7 +381,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this < val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean belowThan(int val);
 
@@ -394,7 +394,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this <= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean belowOrEqual(int val);
 
@@ -407,7 +407,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this > val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean aboveThan(int val);
 
@@ -420,7 +420,7 @@
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this >= val}
      *
-     * @since 1.0
+     * @since 19.0
      */
     boolean aboveOrEqual(int val);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,14 +43,14 @@
 /**
  * The root of the interface hierarchy for machine-word-sized values.
  *
- * @since 1.0
+ * @since 19.0
  */
 public interface WordBase {
 
     /**
      * Conversion to a Java primitive value.
      *
-     * @since 1.0
+     * @since 19.0
      */
     long rawValue();
 
@@ -59,7 +59,7 @@
      * the other word based equality routines. In general you should never be statically calling
      * this method anyway.
      *
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     @Deprecated
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -47,7 +47,7 @@
 /**
  * Provides factory method to create machine-word-sized values.
  *
- * @since 1.0
+ * @since 19.0
  */
 public final class WordFactory {
 
@@ -60,7 +60,7 @@
      *
      * @return the constant 0.
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.ZERO)
     public static <T extends WordBase> T zero() {
@@ -73,7 +73,7 @@
      *
      * @return the null pointer.
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.ZERO)
     public static <T extends PointerBase> T nullPointer() {
@@ -87,7 +87,7 @@
      * @param val a 64 bit unsigned value
      * @return the value cast to Word
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
     public static <T extends UnsignedWord> T unsigned(long val) {
@@ -101,7 +101,7 @@
      * @param val a 64 bit unsigned value
      * @return the value cast to PointerBase
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
     public static <T extends PointerBase> T pointer(long val) {
@@ -115,7 +115,7 @@
      * @param val a 32 bit unsigned value
      * @return the value cast to Word
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED)
     public static <T extends UnsignedWord> T unsigned(int val) {
@@ -129,7 +129,7 @@
      * @param val a 64 bit signed value
      * @return the value cast to Word
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED)
     public static <T extends SignedWord> T signed(long val) {
@@ -143,7 +143,7 @@
      * @param val a 32 bit signed value
      * @return the value cast to Word
      *
-     * @since 1.0
+     * @since 19.0
      */
     @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED)
     public static <T extends SignedWord> T signed(int val) {
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,7 +29,7 @@
  * This package provides a low-level mechanism to use machine-word-sized values in Java. The package
  * can only be used in the context of native images or Graal snippets.
  *
- * @since 1.0
+ * @since 19.0
  */
 
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -139,7 +139,7 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);
         ParameterNode arg = graph.getParameter(0);
         if (snippet.expectParameterUsage()) {
@@ -148,6 +148,5 @@
         } else {
             Assert.assertTrue("expected no usages of ParameterNode", arg == null || arg.hasNoUsages());
         }
-        return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -249,7 +249,7 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
         for (int i = 0; i < anchors.size(); i++) {
             ControlFlowAnchorNode a = anchors.get(i);
@@ -265,6 +265,5 @@
             NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass());
             Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count());
         }
-        return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/IterationDirectiveTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -54,13 +54,11 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.TYPE);
         Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count());
 
         LoopBeginNode loopBeginNode = loopBeginNodes.first();
         Assert.assertEquals("loop frequency of " + loopBeginNode, 128, loopBeginNode.loopFrequency(), 0);
-
-        return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -138,11 +138,10 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
         for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
             Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass());
         }
-        return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,6 +24,8 @@
 
 package org.graalvm.compiler.api.directives.test;
 
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
@@ -37,6 +39,15 @@
 
 public class ProbabilityDirectiveTest extends GraalCompilerTest {
 
+    /**
+     * Called before a test is compiled.
+     */
+    @Override
+    protected void before(ResolvedJavaMethod method) {
+        // don't let -Xcomp pollute profile
+        method.reprofile();
+    }
+
     public static int branchProbabilitySnippet(int arg) {
         if (GraalDirectives.injectBranchProbability(0.125, arg > 0)) {
             GraalDirectives.controlFlowAnchor(); // prevent removal of the if
@@ -68,7 +79,7 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
         Assert.assertEquals("IfNode count", 1, ifNodes.count());
 
@@ -81,8 +92,6 @@
             oneSuccessor = ifNode.falseSuccessor();
         }
         Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(oneSuccessor), 0);
-
-        return true;
     }
 
     private static int returnValue(AbstractBeginNode b) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -2963,17 +2963,17 @@
 
     public void annotatePatchingImmediate(int pos, Instruction instruction, int operandSizeBits, int offsetBits, int shift) {
         if (codePatchingAnnotationConsumer != null) {
-            codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(pos, instruction, operandSizeBits, offsetBits, shift));
+            codePatchingAnnotationConsumer.accept(new SingleInstructionAnnotation(pos, instruction, operandSizeBits, offsetBits, shift));
         }
     }
 
-    void annotatePatchingImmediateNativeAddress(int pos, int operandSizeBits, int numInstrs) {
+    void annotateImmediateMovSequence(int pos, int numInstrs) {
         if (codePatchingAnnotationConsumer != null) {
-            codePatchingAnnotationConsumer.accept(new MovSequenceAnnotation(pos, operandSizeBits, numInstrs));
+            codePatchingAnnotationConsumer.accept(new MovSequenceAnnotation(pos, numInstrs));
         }
     }
 
-    public static class OperandDataAnnotation extends CodeAnnotation {
+    public static class SingleInstructionAnnotation extends CodeAnnotation {
 
         /**
          * The size of the operand, in bytes.
@@ -2983,7 +2983,7 @@
         public final Instruction instruction;
         public final int shift;
 
-        OperandDataAnnotation(int instructionPosition, Instruction instruction, int operandSizeBits, int offsetBits, int shift) {
+        SingleInstructionAnnotation(int instructionPosition, Instruction instruction, int operandSizeBits, int offsetBits, int shift) {
             super(instructionPosition);
             this.operandSizeBits = operandSizeBits;
             this.offsetBits = offsetBits;
@@ -2997,12 +2997,10 @@
         /**
          * The size of the operand, in bytes.
          */
-        public final int operandSizeBits;
         public final int numInstrs;
 
-        MovSequenceAnnotation(int instructionPosition, int operandSizeBits, int numInstrs) {
+        MovSequenceAnnotation(int instructionPosition, int numInstrs) {
             super(instructionPosition);
-            this.operandSizeBits = operandSizeBits;
             this.numInstrs = numInstrs;
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -339,10 +339,13 @@
      * Generates a 64-bit immediate move code sequence.
      *
      * @param dst general purpose register. May not be null, stackpointer or zero-register.
-     * @param imm
+     * @param imm the value to move into the register
+     * @param annotateImm Flag denoting if annotation should be added.
      */
-    private void mov64(Register dst, long imm) {
+    private void mov64(Register dst, long imm, boolean annotateImm) {
         // We have to move all non zero parts of the immediate in 16-bit chunks
+        int numMovs = 0;
+        int pos = position();
         boolean firstMove = true;
         for (int offset = 0; offset < 64; offset += 16) {
             int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
@@ -355,8 +358,12 @@
             } else {
                 movk(64, dst, chunk, offset);
             }
+            ++numMovs;
         }
         assert !firstMove;
+        if (annotateImm) {
+            annotateImmediateMovSequence(pos, numMovs);
+        }
     }
 
     /**
@@ -378,7 +385,6 @@
      */
     public void mov(Register dst, long imm, boolean annotateImm) {
         assert dst.getRegisterCategory().equals(CPU);
-        int pos = position();
         if (imm == 0L) {
             movx(dst, zr);
         } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
@@ -391,10 +397,7 @@
             mov(dst, (int) imm);
             sxt(64, 32, dst, dst);
         } else {
-            mov64(dst, imm);
-            if (annotateImm) {
-                annotatePatchingImmediateNativeAddress(pos, 64, 4);
-            }
+            mov64(dst, imm, annotateImm);
         }
     }
 
@@ -448,7 +451,7 @@
             }
         }
         if (annotateImm) {
-            annotatePatchingImmediateNativeAddress(pos, 48, 3);
+            annotateImmediateMovSequence(pos, 3);
         }
         assert !firstMove;
     }
@@ -1805,24 +1808,24 @@
     }
 
     /**
-     * Emits elf patchable adrp add sequence.
+     * Emits elf patchable adrp ldr sequence.
      */
-    public void adrAddRel(int srcSize, Register result, AArch64Address a) {
+    public void adrpLdr(int srcSize, Register result, AArch64Address a) {
         if (codePatchingAnnotationConsumer != null) {
-            codePatchingAnnotationConsumer.accept(new ADRADDPRELMacroInstruction(position()));
+            codePatchingAnnotationConsumer.accept(new AdrpLdrMacroInstruction(position()));
         }
         super.adrp(a.getBase());
         this.ldr(srcSize, result, a);
     }
 
-    public static class ADRADDPRELMacroInstruction extends CodeAnnotation implements MacroInstruction {
-        public ADRADDPRELMacroInstruction(int position) {
+    public static class AdrpLdrMacroInstruction extends CodeAnnotation implements MacroInstruction {
+        public AdrpLdrMacroInstruction(int position) {
             super(position);
         }
 
         @Override
         public String toString() {
-            return "ADR_PREL_PG";
+            return "ADRP_LDR";
         }
 
         @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64AsmOptions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,6 +27,7 @@
 public class AMD64AsmOptions {
     public static final boolean UseNormalNop = false;
     public static final boolean UseAddressNop = true;
+    public static final boolean UseIntelNops = true;
     public static final boolean UseIncDec = true;
     public static final boolean UseXmmLoadAndClearUpper = true;
     public static final boolean UseXmmRegToRegMoveAll = true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,6 +29,7 @@
 import static jdk.vm.ci.amd64.AMD64.XMM;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
 import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
+import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIntelNops;
 import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
@@ -2295,125 +2296,10 @@
         }
 
         if (UseAddressNop) {
-            //
-            // Using multi-bytes nops "0x0F 0x1F [Address]" for AMD.
-            // 1: 0x90
-            // 2: 0x66 0x90
-            // 3: 0x66 0x66 0x90 (don't use "0x0F 0x1F 0x00" - need patching safe padding)
-            // 4: 0x0F 0x1F 0x40 0x00
-            // 5: 0x0F 0x1F 0x44 0x00 0x00
-            // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00
-            // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
-            // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
-            // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
-            // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
-            // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
-
-            // The rest coding is AMD specific - use consecutive Address nops
-
-            // 12: 0x66 0x0F 0x1F 0x44 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
-            // 13: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
-            // 14: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
-            // 15: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
-            // 16: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
-            // Size prefixes (0x66) are added for larger sizes
-
-            while (i >= 22) {
-                i -= 11;
-                emitByte(0x66); // size prefix
-                emitByte(0x66); // size prefix
-                emitByte(0x66); // size prefix
-                addrNop8();
-            }
-            // Generate first nop for size between 21-12
-            switch (i) {
-                case 21:
-                    i -= 11;
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 20:
-                case 19:
-                    i -= 10;
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 18:
-                case 17:
-                    i -= 9;
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 16:
-                case 15:
-                    i -= 8;
-                    addrNop8();
-                    break;
-                case 14:
-                case 13:
-                    i -= 7;
-                    addrNop7();
-                    break;
-                case 12:
-                    i -= 6;
-                    emitByte(0x66); // size prefix
-                    addrNop5();
-                    break;
-                default:
-                    assert i < 12;
-            }
-
-            // Generate second nop for size between 11-1
-            switch (i) {
-                case 11:
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 10:
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 9:
-                    emitByte(0x66); // size prefix
-                    addrNop8();
-                    break;
-                case 8:
-                    addrNop8();
-                    break;
-                case 7:
-                    addrNop7();
-                    break;
-                case 6:
-                    emitByte(0x66); // size prefix
-                    addrNop5();
-                    break;
-                case 5:
-                    addrNop5();
-                    break;
-                case 4:
-                    addrNop4();
-                    break;
-                case 3:
-                    // Don't use "0x0F 0x1F 0x00" - need patching safe padding
-                    emitByte(0x66); // size prefix
-                    emitByte(0x66); // size prefix
-                    emitByte(0x90); // nop
-                    break;
-                case 2:
-                    emitByte(0x66); // size prefix
-                    emitByte(0x90); // nop
-                    break;
-                case 1:
-                    emitByte(0x90); // nop
-                    break;
-                default:
-                    assert i == 0;
+            if (UseIntelNops) {
+                intelNops(i);
+            } else {
+                amdNops(i);
             }
             return;
         }
@@ -2484,6 +2370,222 @@
         }
     }
 
+    private void amdNops(int count) {
+        int i = count;
+        //
+        // Using multi-bytes nops "0x0F 0x1F [Address]" for AMD.
+        // 1: 0x90
+        // 2: 0x66 0x90
+        // 3: 0x66 0x66 0x90 (don't use "0x0F 0x1F 0x00" - need patching safe padding)
+        // 4: 0x0F 0x1F 0x40 0x00
+        // 5: 0x0F 0x1F 0x44 0x00 0x00
+        // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00
+        // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+        // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+
+        // The rest coding is AMD specific - use consecutive Address nops
+
+        // 12: 0x66 0x0F 0x1F 0x44 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
+        // 13: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x66 0x0F 0x1F 0x44 0x00 0x00
+        // 14: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+        // 15: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+        // 16: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // Size prefixes (0x66) are added for larger sizes
+
+        while (i >= 22) {
+            i -= 11;
+            emitByte(0x66); // size prefix
+            emitByte(0x66); // size prefix
+            emitByte(0x66); // size prefix
+            addrNop8();
+        }
+        // Generate first nop for size between 21-12
+        switch (i) {
+            case 21:
+                i -= 11;
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 20:
+            case 19:
+                i -= 10;
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 18:
+            case 17:
+                i -= 9;
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 16:
+            case 15:
+                i -= 8;
+                addrNop8();
+                break;
+            case 14:
+            case 13:
+                i -= 7;
+                addrNop7();
+                break;
+            case 12:
+                i -= 6;
+                emitByte(0x66); // size prefix
+                addrNop5();
+                break;
+            default:
+                assert i < 12;
+        }
+
+        // Generate second nop for size between 11-1
+        switch (i) {
+            case 11:
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 10:
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 9:
+                emitByte(0x66); // size prefix
+                addrNop8();
+                break;
+            case 8:
+                addrNop8();
+                break;
+            case 7:
+                addrNop7();
+                break;
+            case 6:
+                emitByte(0x66); // size prefix
+                addrNop5();
+                break;
+            case 5:
+                addrNop5();
+                break;
+            case 4:
+                addrNop4();
+                break;
+            case 3:
+                // Don't use "0x0F 0x1F 0x00" - need patching safe padding
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x90); // nop
+                break;
+            case 2:
+                emitByte(0x66); // size prefix
+                emitByte(0x90); // nop
+                break;
+            case 1:
+                emitByte(0x90); // nop
+                break;
+            default:
+                assert i == 0;
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private void intelNops(int count) {
+        //
+        // Using multi-bytes nops "0x0F 0x1F [address]" for Intel
+        // 1: 0x90
+        // 2: 0x66 0x90
+        // 3: 0x66 0x66 0x90 (don't use "0x0F 0x1F 0x00" - need patching safe padding)
+        // 4: 0x0F 0x1F 0x40 0x00
+        // 5: 0x0F 0x1F 0x44 0x00 0x00
+        // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00
+        // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
+        // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+        // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
+
+        // The rest coding is Intel specific - don't use consecutive address nops
+
+        // 12: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x66 0x66 0x66 0x90
+        // 13: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x66 0x66 0x66 0x90
+        // 14: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x66 0x66 0x66 0x90
+        // 15: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00 0x66 0x66 0x66 0x90
+
+        int i = count;
+        while (i >= 15) {
+            // For Intel don't generate consecutive addess nops (mix with regular nops)
+            i -= 15;
+            emitByte(0x66);   // size prefix
+            emitByte(0x66);   // size prefix
+            emitByte(0x66);   // size prefix
+            addrNop8();
+            emitByte(0x66);   // size prefix
+            emitByte(0x66);   // size prefix
+            emitByte(0x66);   // size prefix
+            emitByte(0x90);
+            // nop
+        }
+        switch (i) {
+            case 14:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 13:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 12:
+                addrNop8();
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x66); // size prefix
+                emitByte(0x90);
+                // nop
+                break;
+            case 11:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 10:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 9:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 8:
+                addrNop8();
+                break;
+            case 7:
+                addrNop7();
+                break;
+            case 6:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 5:
+                addrNop5();
+                break;
+            case 4:
+                addrNop4();
+                break;
+            case 3:
+                // Don't use "0x0F 0x1F 0x00" - need patching safe padding
+                emitByte(0x66); // size prefix
+                // fall through
+            case 2:
+                emitByte(0x66); // size prefix
+                // fall through
+            case 1:
+                emitByte(0x90);
+                // nop
+                break;
+            default:
+                assert i == 0;
+        }
+    }
+
     public final void orl(Register dst, Register src) {
         OR.rmOp.emit(this, DWORD, dst, src);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,6 +30,8 @@
 import java.util.Map;
 import java.util.function.Consumer;
 
+import org.graalvm.compiler.debug.GraalError;
+
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.TargetDescription;
@@ -164,7 +166,7 @@
         Label label = labelsWithPatches;
         while (label != null) {
             if (label.patchPositions != null) {
-                throw new InternalError("Label used by instructions at following offsets has not been bound: " + label.patchPositions);
+                throw new GraalError("Label used by instructions at following offsets has not been bound: %s", label.patchPositions);
             }
             Label next = label.nextWithPatches;
             label.nextWithPatches = null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Buffer.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,12 +24,13 @@
 
 package org.graalvm.compiler.asm;
 
-import org.graalvm.compiler.core.common.NumUtil;
-
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Arrays;
 
+import org.graalvm.compiler.core.common.NumUtil;
+import org.graalvm.compiler.serviceprovider.BufferUtil;
+
 /**
  * Code buffer management for the assembler.
  */
@@ -48,7 +49,7 @@
 
     public void setPosition(int position) {
         assert position >= 0 && position <= data.limit();
-        data.position(position);
+        BufferUtil.asBaseBuffer(data).position(position);
     }
 
     /**
@@ -93,7 +94,7 @@
             byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
             ByteBuffer newData = ByteBuffer.wrap(newBuf);
             newData.order(data.order());
-            newData.position(data.position());
+            BufferUtil.asBaseBuffer(newData).position(data.position());
             data = newData;
         }
     }
@@ -170,6 +171,6 @@
     }
 
     public void reset() {
-        data.clear();
+        BufferUtil.asBaseBuffer(data).clear();
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Label.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,6 +26,8 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.compiler.debug.GraalError;
+
 /**
  * This class represents a label within assembly code.
  */
@@ -71,7 +73,9 @@
      * {@link #addPatchAt(int, Assembler)}.
      */
     protected void bind(int pos, Assembler asm) {
-        assert pos >= 0;
+        if (pos < 0) {
+            throw new GraalError("Cannot bind label to negative position %d", pos);
+        }
         this.position = pos;
         if (patchPositions != null) {
             for (int i = 0; i < patchPositions.size(); ++i) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,6 +33,7 @@
 import java.util.function.BiConsumer;
 
 import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.serviceprovider.BufferUtil;
 
 import jdk.vm.ci.code.site.DataSectionReference;
 import jdk.vm.ci.meta.SerializableConstant;
@@ -376,11 +377,11 @@
         assert buffer.remaining() >= sectionSize;
         int start = buffer.position();
         for (Data d : dataItems) {
-            buffer.position(start + d.ref.getOffset());
+            BufferUtil.asBaseBuffer(buffer).position(start + d.ref.getOffset());
             onEmit.accept(d.ref, d.getSize());
             d.emit(buffer, patch);
         }
-        buffer.position(start + sectionSize);
+        BufferUtil.asBaseBuffer(buffer).position(start + sectionSize);
     }
 
     public Data findData(DataSectionReference ref) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64BitFieldTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Arm Limited and affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.core.aarch64.test;
+
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.aarch64.AArch64BitFieldOp;
+import org.junit.Test;
+
+import java.util.function.Predicate;
+
+public class AArch64BitFieldTest extends AArch64MatchRuleTest {
+    private static final Predicate<LIRInstruction> predicate = op -> (op instanceof AArch64BitFieldOp);
+
+    private void testAndCheckLIR(String method, String negativeMethod, Object input) {
+        test(method, input);
+        checkLIR(method, predicate, 1);
+        test(negativeMethod, input);
+        checkLIR(negativeMethod, predicate, 0);
+    }
+
+    /**
+     * unsigned bit field extract int.
+     */
+    public static int extractInt(int input) {
+        return (input >>> 6) & 0xffff;
+    }
+
+    /**
+     * unsigned bit field extract int (negative cases).
+     */
+    public static int invalidExtractInt(int input) {
+        int result = 0;
+        result += ((input >>> 10) & 0xfff0);    // Invalid mask
+        result += ((input >>> 2) & 0x7fffffff); // Bit field width too large
+        result += ((input >>> 16) & 0x1ffff);   // Width + lsb exceeds limit
+        return result;
+    }
+
+    @Test
+    public void testExtractInt() {
+        testAndCheckLIR("extractInt", "invalidExtractInt", 0x12345678);
+    }
+
+    /**
+     * unsigned bit field extract long.
+     */
+    public static long extractLong(long input) {
+        return (input >>> 25) & 0xffffffffL;
+    }
+
+    /**
+     * unsigned bit field extract long (negative cases).
+     */
+    public static long invalidExtractLong(long input) {
+        long result = 0L;
+        result += ((input >>> 10) & 0x230L);                // Invalid mask
+        result += ((input >>> 2) & 0x7fffffffffffffffL);    // Bit field width too large
+        result += ((input >>> 62) & 0x7L);                  // Width + lsb exceeds limit
+        return result;
+    }
+
+    @Test
+    public void testExtractLong() {
+        testAndCheckLIR("extractLong", "invalidExtractLong", 0xfedcba9876543210L);
+    }
+
+    /**
+     * unsigned bit field insert int.
+     */
+    public static int insertInt(int input) {
+        return (input & 0xfff) << 10;
+    }
+
+    /**
+     * unsigned bit field insert int (negative cases).
+     */
+    public static int invalidInsertInt(int input) {
+        int result = 0;
+        result += ((input & 0xe) << 25);        // Invalid mask
+        result += ((input & 0x7fffffff) << 1);  // Bit field width too large
+        result += ((input & 0x1ffff) << 16);    // Width + lsb exceeds limit
+        return result;
+    }
+
+    @Test
+    public void testInsertInt() {
+        testAndCheckLIR("insertInt", "invalidInsertInt", 0xcafebabe);
+    }
+
+    /**
+     * unsigned bit field insert long.
+     */
+    public static long insertLong(long input) {
+        return (input & 0x3fffffffffffL) << 7;
+    }
+
+    /**
+     * unsigned bit field insert long (negative cases).
+     */
+    public static long invalidInsertLong(long input) {
+        long result = 0L;
+        result += ((input & 0x1a) << 39);                   // Invalid mask
+        result += ((input & 0x7fffffffffffffffL) << 1);     // Bit field width too large
+        result += ((input & 0x3fffffff) << 52);             // Width + lsb exceeds limit
+        return result;
+    }
+
+    @Test
+    public void testInsertLong() {
+        testAndCheckLIR("insertLong", "invalidInsertLong", 0xdeadbeefdeadbeefL);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,6 +26,7 @@
 package org.graalvm.compiler.core.aarch64;
 
 import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
@@ -42,6 +43,7 @@
 import org.graalvm.compiler.lir.LabelRef;
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
+import org.graalvm.compiler.lir.aarch64.AArch64BitFieldOp;
 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -65,7 +67,7 @@
 
 public class AArch64NodeMatchRules extends NodeMatchRules {
     private static final EconomicMap<Class<? extends Node>, AArch64ArithmeticOp> nodeOpMap;
-
+    private static final EconomicMap<Class<? extends BinaryNode>, AArch64BitFieldOp.BitFieldOpCode> bitFieldOpMap;
     private static final EconomicMap<Class<? extends BinaryNode>, AArch64MacroAssembler.ShiftType> shiftTypeMap;
 
     static {
@@ -76,6 +78,10 @@
         nodeOpMap.put(OrNode.class, AArch64ArithmeticOp.OR);
         nodeOpMap.put(XorNode.class, AArch64ArithmeticOp.XOR);
 
+        bitFieldOpMap = EconomicMap.create(Equivalence.IDENTITY, 2);
+        bitFieldOpMap.put(UnsignedRightShiftNode.class, AArch64BitFieldOp.BitFieldOpCode.UBFX);
+        bitFieldOpMap.put(LeftShiftNode.class, AArch64BitFieldOp.BitFieldOpCode.UBFIZ);
+
         shiftTypeMap = EconomicMap.create(Equivalence.IDENTITY, 3);
         shiftTypeMap.put(LeftShiftNode.class, AArch64MacroAssembler.ShiftType.LSL);
         shiftTypeMap.put(RightShiftNode.class, AArch64MacroAssembler.ShiftType.ASR);
@@ -101,6 +107,19 @@
         return getLIRGeneratorTool().moveSp(value);
     }
 
+    private ComplexMatchResult emitBitField(AArch64BitFieldOp.BitFieldOpCode op, ValueNode value, int lsb, int width) {
+        assert op != null;
+        assert value.getStackKind().isNumericInteger();
+
+        return builder -> {
+            Value a = operand(value);
+            Variable result = gen.newVariable(LIRKind.combine(a));
+            AllocatableValue src = moveSp(gen.asAllocatable(a));
+            gen.append(new AArch64BitFieldOp(op, result, src, lsb, width));
+            return result;
+        };
+    }
+
     private ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode value, BinaryNode shift,
                     boolean isShiftNot) {
         AArch64MacroAssembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass());
@@ -133,6 +152,40 @@
         };
     }
 
+    @MatchRule("(And (UnsignedRightShift=shift a Constant=b) Constant=c)")
+    @MatchRule("(LeftShift=shift (And a Constant=c) Constant=b)")
+    public ComplexMatchResult unsignedBitField(BinaryNode shift, ValueNode a, ConstantNode b, ConstantNode c) {
+        JavaKind srcKind = a.getStackKind();
+        assert srcKind.isNumericInteger();
+        AArch64BitFieldOp.BitFieldOpCode op = bitFieldOpMap.get(shift.getClass());
+        assert op != null;
+        int distance = b.asJavaConstant().asInt();
+        long mask = c.asJavaConstant().asLong();
+
+        // The Java(R) Language Specification CHAPTER 15.19 Shift Operators says:
+        // "If the promoted type of the left-hand operand is int(long), then only the five(six)
+        // lowest-order bits of the right-hand operand are used as the shift distance."
+        distance = distance & (srcKind == JavaKind.Int ? 0x1f : 0x3f);
+
+        // Constraint 1: Mask plus one should be a power-of-2 integer.
+        if (!CodeUtil.isPowerOf2(mask + 1)) {
+            return null;
+        }
+        int width = CodeUtil.log2(mask + 1);
+        int srcBits = srcKind.getBitCount();
+        // Constraint 2: Bit field width is less than 31(63) for int(long) as any bit field move
+        // operations can be done by a single shift instruction if the width is 31(63).
+        if (width >= srcBits - 1) {
+            return null;
+        }
+        // Constraint 3: Sum of bit field width and the shift distance is less or equal to 32(64)
+        // for int(long) as the specification of AArch64 bit field instructions.
+        if (width + distance > srcBits) {
+            return null;
+        }
+        return emitBitField(op, a, distance, width);
+    }
+
     @MatchRule("(Add=binary a (LeftShift=shift b Constant))")
     @MatchRule("(Add=binary a (RightShift=shift b Constant))")
     @MatchRule("(Add=binary a (UnsignedRightShift=shift b Constant))")
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -450,6 +450,13 @@
         }
     }
 
+    public Value emitBinaryMemory(VexRVMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+        assert (size.isXmmType() && supportAVX());
+        Variable result = getLIRGen().newVariable(LIRKind.combine(a));
+        getLIRGen().append(new AMD64VectorBinary.AVXBinaryMemoryOp(op, getRegisterSize(result), result, a, location, state));
+        return result;
+    }
+
     public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
         Variable result = getLIRGen().newVariable(LIRKind.combine(a));
         getLIRGen().append(new AMD64Binary.MemoryTwoOp(op, size, result, a, location, state));
@@ -1339,7 +1346,7 @@
         return result;
     }
 
-    private boolean supportAVX() {
+    public boolean supportAVX() {
         TargetDescription target = getLIRGen().target();
         return ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -576,13 +576,10 @@
     }
 
     @Override
-    public Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value arrayPointer, Value arrayLength, Value... searchValues) {
-        Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
-        Value[] allocatableSearchValues = new Value[searchValues.length];
-        for (int i = 0; i < searchValues.length; i++) {
-            allocatableSearchValues[i] = asAllocatable(searchValues[i]);
-        }
-        append(new AMD64ArrayIndexOfOp(kind, findTwoConsecutive, getVMPageSize(), getMaxVectorSize(), this, result, asAllocatable(arrayPointer), asAllocatable(arrayLength), allocatableSearchValues));
+    public Variable emitArrayIndexOf(JavaKind arrayKind, JavaKind valueKind, boolean findTwoConsecutive, Value arrayPointer, Value arrayLength, Value fromIndex, Value... searchValues) {
+        Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
+        append(new AMD64ArrayIndexOfOp(arrayKind, valueKind, findTwoConsecutive, getMaxVectorSize(), this, result,
+                        asAllocatable(arrayPointer), asAllocatable(arrayLength), asAllocatable(fromIndex), searchValues));
         return result;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,11 +33,18 @@
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VADDSD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VADDSS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VMULSD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VMULSS;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VSUBSD;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VSUBSS;
 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SD;
 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SS;
 
+import org.graalvm.compiler.asm.amd64.AMD64Assembler;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
@@ -380,7 +387,7 @@
     @MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))")
     public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) {
         assert compare.condition() == CanonicalCondition.EQ;
-        if (value == cas.getExpectedValue() && cas.usages().count() == 1) {
+        if (value == cas.getExpectedValue() && cas.hasExactlyOneUsage()) {
             return builder -> {
                 LIRKind kind = getLirKind(cas);
                 LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
@@ -403,7 +410,7 @@
     public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
         JavaConstant constant = value.asJavaConstant();
         assert compare.condition() == CanonicalCondition.EQ;
-        if (constant != null && cas.usages().count() == 1) {
+        if (constant != null && cas.hasExactlyOneUsage()) {
             long constantValue = constant.asLong();
             boolean successIsTrue;
             if (constantValue == 0) {
@@ -463,12 +470,22 @@
                         getState(access));
     }
 
+    private ComplexMatchResult binaryRead(AMD64Assembler.VexRVMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
+        assert size == SS || size == SD;
+        return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
+                        getState(access));
+    }
+
     @MatchRule("(Add value Read=access)")
     @MatchRule("(Add value FloatingRead=access)")
     public ComplexMatchResult addMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
-            return binaryRead(SSEOp.ADD, size, value, access);
+            if (getArithmeticLIRGenerator().supportAVX()) {
+                return binaryRead(size == SS ? VADDSS : VADDSD, size, value, access);
+            } else {
+                return binaryRead(SSEOp.ADD, size, value, access);
+            }
         } else {
             return binaryRead(ADD.getRMOpcode(size), size, value, access);
         }
@@ -479,7 +496,11 @@
     public ComplexMatchResult subMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
-            return binaryRead(SSEOp.SUB, size, value, access);
+            if (getArithmeticLIRGenerator().supportAVX()) {
+                return binaryRead(size == SS ? VSUBSS : VSUBSD, size, value, access);
+            } else {
+                return binaryRead(SSEOp.SUB, size, value, access);
+            }
         } else {
             return binaryRead(SUB.getRMOpcode(size), size, value, access);
         }
@@ -490,7 +511,11 @@
     public ComplexMatchResult mulMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
-            return binaryRead(SSEOp.MUL, size, value, access);
+            if (getArithmeticLIRGenerator().supportAVX()) {
+                return binaryRead(size == SS ? VMULSS : VMULSD, size, value, access);
+            } else {
+                return binaryRead(SSEOp.MUL, size, value, access);
+            }
         } else {
             return binaryRead(AMD64RMOp.IMUL, size, value, access);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,10 +26,11 @@
 
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionStability;
 import org.graalvm.compiler.options.OptionType;
 
 /**
- * This class encapsulates options that control the behavior of the Graal compiler.
+ * This class encapsulates options that control the behavior of the GraalVM compiler.
  */
 // @formatter:off
 public final class GraalOptions {
@@ -167,6 +168,9 @@
     public static final OptionKey<Boolean> ConditionalElimination = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
+    public static final OptionKey<Integer> ConditionalEliminationMaxIterations = new OptionKey<>(4);
+
+    @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> RawConditionalElimination = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
@@ -238,9 +242,6 @@
     public static final OptionKey<Boolean> OptImplicitNullChecks = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionKey<Boolean> OptClearNonLiveLocals = new OptionKey<>(true);
-
-    @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> OptLoopTransform = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
@@ -273,7 +274,7 @@
     @Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug)
     public static final OptionKey<Boolean> UseSnippetGraphCache = new OptionKey<>(true);
 
-    @Option(help = "file:doc-files/TraceInliningHelp.txt", type = OptionType.Debug)
+    @Option(help = "file:doc-files/TraceInliningHelp.txt", type = OptionType.Debug, stability = OptionStability.STABLE)
     public static final OptionKey<Boolean> TraceInlining = new OptionKey<>(false);
 
     @Option(help = "Enable inlining decision tracing in stubs and snippets.", type = OptionType.Debug)
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java	Fri Jun 28 14:36:42 2019 +0530
@@ -88,7 +88,7 @@
         this.referenceCompressionMask = referenceCompressionMask;
         this.derivedReferenceBase = derivedReferenceBase;
 
-        assert this.referenceCompressionMask == 0 || this.referenceMask == this.referenceCompressionMask : "mixing compressed and uncompressed references is untested";
+        assert this.referenceCompressionMask == 0 || this.referenceMask == this.referenceCompressionMask : "mixing compressed and uncompressed references is unsupported";
         assert derivedReferenceBase == null || !derivedReferenceBase.getValueKind(LIRKind.class).isDerivedReference() : "derived reference can't have another derived reference as base";
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpeculativeExecutionAttacksMitigations.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpeculativeExecutionAttacksMitigations.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,6 +27,7 @@
 import org.graalvm.compiler.options.EnumOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionStability;
 import org.graalvm.compiler.options.OptionType;
 
 public enum SpeculativeExecutionAttacksMitigations {
@@ -39,7 +40,7 @@
         // @formatter:off
         @Option(help = "file:doc-files/MitigateSpeculativeExecutionAttacksHelp.txt")
         public static final EnumOptionKey<SpeculativeExecutionAttacksMitigations> MitigateSpeculativeExecutionAttacks = new EnumOptionKey<>(None);
-        @Option(help = "Use index masking after bounds check to mitigate speculative execution attacks.", type = OptionType.User)
+        @Option(help = "Use index masking after bounds check to mitigate speculative execution attacks.", type = OptionType.User, stability = OptionStability.STABLE)
         public static final OptionKey<Boolean> UseIndexMasking = new OptionKey<>(false);
         // @formatter:on
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -150,6 +150,13 @@
     }
 
     /**
+     * Returns true if NaN is included in the value described by this stamp.
+     */
+    public boolean canBeNaN() {
+        return !nonNaN;
+    }
+
+    /**
      * Returns true if this stamp represents the NaN value.
      */
     public boolean isNaN() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Fri Jun 28 14:36:42 2019 +0530
@@ -151,7 +151,7 @@
     public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
         JavaConstant constant = value.asJavaConstant();
         assert compare.condition() == CanonicalCondition.EQ;
-        if (constant != null && cas.usages().count() == 1) {
+        if (constant != null && cas.hasExactlyOneUsage()) {
             long constantValue = constant.asLong();
             boolean successIsTrue;
             if (constantValue == 0) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CanonicalizedConversionTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CanonicalizedConversionTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,7 +41,7 @@
 public class CanonicalizedConversionTest extends GraalCompilerTest {
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         int reinterpretCount = 0;
         int floatEqualsCount = 0;
         int addCount = 0;
@@ -59,7 +59,6 @@
         Assert.assertEquals(1, reinterpretCount);
         Assert.assertEquals(1, floatEqualsCount);
         Assert.assertEquals(2, addCount);
-        return true;
     }
 
     @Test
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Fri Jun 28 14:36:42 2019 +0530
@@ -66,6 +66,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.PhaseSuite;
@@ -73,9 +74,9 @@
 import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
 import org.graalvm.compiler.phases.contract.VerifyNodeCosts;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -127,7 +128,7 @@
 
         protected String getClassPath() {
             String bootclasspath;
-            if (Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
                 bootclasspath = System.getProperty("sun.boot.class.path");
             } else {
                 bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
@@ -139,7 +140,7 @@
             if (className.equals("module-info") || className.startsWith("META-INF.versions.")) {
                 return false;
             }
-            if (!Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC > 8) {
                 // @formatter:off
                 /*
                  * Work around to prevent:
@@ -247,7 +248,7 @@
 
         List<String> errors = Collections.synchronizedList(new ArrayList<>());
 
-        List<VerifyPhase<PhaseContext>> verifiers = new ArrayList<>();
+        List<VerifyPhase<CoreProviders>> verifiers = new ArrayList<>();
 
         // If you add a new type to test here, be sure to add appropriate
         // methods to the BadUsageWithEquals class below
@@ -270,6 +271,7 @@
         verifiers.add(new VerifySystemPropertyUsage());
         verifiers.add(new VerifyInstanceOfUsage());
         verifiers.add(new VerifyGraphAddUsage());
+        verifiers.add(new VerifyBufferUsage());
         verifiers.add(new VerifyGetOptionsUsage());
         verifiers.add(new VerifyUnsafeAccess());
 
@@ -413,14 +415,14 @@
      * @param metaAccess
      * @param verifiers
      */
-    private static void checkClass(Class<?> c, MetaAccessProvider metaAccess, List<VerifyPhase<PhaseContext>> verifiers) {
+    private static void checkClass(Class<?> c, MetaAccessProvider metaAccess, List<VerifyPhase<CoreProviders>> verifiers) {
         if (Node.class.isAssignableFrom(c)) {
             if (c.getAnnotation(NodeInfo.class) == null) {
                 throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
             }
             VerifyNodeCosts.verifyNodeClass(c);
         }
-        for (VerifyPhase<PhaseContext> verifier : verifiers) {
+        for (VerifyPhase<CoreProviders> verifier : verifiers) {
             verifier.verifyClass(c, metaAccess);
         }
     }
@@ -445,8 +447,8 @@
     /**
      * Checks the invariants for a single graph.
      */
-    private static void checkGraph(List<VerifyPhase<PhaseContext>> verifiers, HighTierContext context, StructuredGraph graph) {
-        for (VerifyPhase<PhaseContext> verifier : verifiers) {
+    private static void checkGraph(List<VerifyPhase<CoreProviders>> verifiers, HighTierContext context, StructuredGraph graph) {
+        for (VerifyPhase<CoreProviders> verifier : verifiers) {
             if (!(verifier instanceof VerifyUsageWithEquals) || shouldVerifyEquals(graph.method())) {
                 verifier.apply(graph, context);
             } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,8 +24,6 @@
 
 package org.graalvm.compiler.core.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -34,13 +32,13 @@
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerTestNode;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
 
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
     private StructuredGraph getCanonicalizedGraph(String name) {
         StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         return graph;
     }
 
@@ -57,7 +55,7 @@
             StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO);
             assertEquals(referenceGraph, graph);
         }
-        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, getProviders());
         for (int i = 1; i < 4; i++) {
             StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i);
             assertEquals(referenceGraph, graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class CompareCanonicalizerTest2 extends GraalCompilerTest {
@@ -36,7 +35,7 @@
 
     private StructuredGraph getCanonicalizedGraph(String name) {
         StructuredGraph graph = getRegularGraph(name);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,12 +29,12 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -238,7 +238,7 @@
 
     protected void assertCanonicallyEqual(String snippet, String reference) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,11 +28,11 @@
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -94,7 +94,7 @@
 
     private void test(String snippet, int guardCount) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new ConditionalEliminationPhase(true).apply(graph, context);
         Assert.assertEquals(guardCount, graph.getNodes().filter(GuardNode.class).count());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,8 +29,8 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -310,7 +310,7 @@
     }
 
     @Override
-    protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
+    protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, CoreProviders context, boolean applyLowering) {
         super.prepareGraph(graph, canonicalizer, context, applyLowering);
         graph.clearAllStateAfter();
         graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,12 +35,12 @@
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
 import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -71,7 +71,7 @@
     public void test1() {
         StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
 
         /* Convert the LoadIndexNode to ReadNode with floating guards. */
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,11 +29,11 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
 import org.junit.Assert;
 import org.junit.Test;
@@ -48,7 +48,7 @@
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
 
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
 
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest16.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest16.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,6 +32,7 @@
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.junit.Before;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -41,6 +42,13 @@
  */
 public class ConditionalEliminationTest16 extends ConditionalEliminationTestBase {
 
+    @Before
+    public void resetType() {
+        parameterType = null;
+    }
+
+    Class<?> parameterType;
+
     public static int testCastExactInstance(Object object) {
         if (object.getClass() == Integer.class) {
             return ((Integer) object).intValue();
@@ -50,35 +58,91 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
-        for (ParameterNode param : graph.getNodes().filter(ParameterNode.class)) {
-            if (param.index() == 0) {
-                ParameterNode newParam = new ParameterNode(0, StampPair.createSingle(StampFactory.object(TypeReference.createExactTrusted(getMetaAccess().lookupJavaType(Integer.class)))));
-                graph.addWithoutUnique(newParam);
-                param.replaceAtUsages(newParam);
-                param.safeDelete();
-                break;
+    protected void checkHighTierGraph(StructuredGraph graph) {
+        if (parameterType != null) {
+            for (ParameterNode param : graph.getNodes().filter(ParameterNode.class)) {
+                if (param.index() == 0) {
+                    ParameterNode newParam = new ParameterNode(0, StampPair.createSingle(StampFactory.object(TypeReference.createExactTrusted(getMetaAccess().lookupJavaType(parameterType)))));
+                    graph.addWithoutUnique(newParam);
+                    param.replaceAtUsages(newParam);
+                    param.safeDelete();
+                    break;
+                }
             }
+            new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
         }
-        new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
-        return super.checkHighTierGraph(graph);
+        super.checkHighTierGraph(graph);
     }
 
     @Override
-    protected boolean checkMidTierGraph(StructuredGraph graph) {
+    protected void checkMidTierGraph(StructuredGraph graph) {
         int count = 0;
         for (PiNode node : graph.getNodes().filter(PiNode.class)) {
             assertTrue(node.getGuard() != null, "must have guarding node");
             count++;
         }
         assertTrue(count > 0, "expected at least one Pi");
-        return super.checkMidTierGraph(graph);
+        super.checkMidTierGraph(graph);
     }
 
     @Test
     public void test1() {
+        parameterType = Integer.class;
         ResolvedJavaMethod method = getResolvedJavaMethod("testCastExactInstance");
         StructuredGraph graph = parseForCompile(method);
         compile(method, graph);
     }
+
+    static class Base {
+        int getValue1() {
+            return 0;
+        }
+
+        Base getBase() {
+            return this;
+        }
+    }
+
+    static class Box extends Base {
+        int value1;
+
+        @Override
+        int getValue1() {
+            return value1;
+        }
+    }
+
+    static class BiggerBox extends Box {
+        int value2;
+
+        int getValue2() {
+            return value2;
+        }
+    }
+
+    public static int testCastExactTwiceInstance(Base base, boolean b) {
+        if (!(base instanceof Box)) {
+            GraalDirectives.deoptimizeAndInvalidate();
+            return -1;
+        }
+        int total = 0;
+        if (base instanceof Box) {
+            Box box = (Box) base;
+            total += box.value1;
+            if (b) {
+                total += System.identityHashCode(base);
+            }
+            total += ((BiggerBox) base).getValue2();
+        }
+        return total;
+    }
+
+    @Test
+    public void test2() {
+        BiggerBox box = new BiggerBox();
+        ResolvedJavaMethod method = getResolvedJavaMethod("testCastExactTwiceInstance");
+        StructuredGraph graph = parseForCompile(method);
+        compile(method, graph);
+        test("testCastExactTwiceInstance", box, false);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,12 +29,12 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -110,7 +110,7 @@
     public void testRedundantCompares() {
         StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
@@ -133,7 +133,7 @@
         StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES);
 
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
@@ -147,7 +147,7 @@
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
 
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
 
         canonicalizer.apply(graph, context);
         new ConditionalEliminationPhase(true).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,20 +25,20 @@
 package org.graalvm.compiler.core.test;
 
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
-import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 
 /**
@@ -68,7 +68,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         try (DebugContext.Scope scope = debug.scope("ConditionalEliminationTest", graph)) {
@@ -93,7 +93,7 @@
         assertEquals(referenceGraph, graph);
     }
 
-    protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
+    protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, CoreProviders context, boolean applyLowering) {
         if (applyLowering) {
             new ConvertDeoptimizeToGuardPhase().apply(graph, context);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
@@ -105,7 +105,7 @@
 
     public void testProxies(String snippet, int expectedProxiesCreated) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
         canonicalizer1.disableSimplification();
         canonicalizer1.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CopyOfVirtualizationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,9 +35,9 @@
 public class CopyOfVirtualizationTest extends GraalCompilerTest {
 
     @Override
-    protected boolean checkMidTierGraph(StructuredGraph graph) {
+    protected void checkMidTierGraph(StructuredGraph graph) {
         assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph);
-        return super.checkMidTierGraph(graph);
+        super.checkMidTierGraph(graph);
     }
 
     public byte byteCopyOfVirtualization(int index) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -483,14 +483,13 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         LoopsData loops = new LoopsData(graph);
         loops.detectedCountedLoops();
         for (IVPropertyNode node : graph.getNodes().filter(IVPropertyNode.class)) {
             node.rewrite(loops);
         }
         assert graph.getNodes().filter(IVPropertyNode.class).isEmpty();
-        return true;
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CustomizedBytecodePatternTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CustomizedBytecodePatternTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,14 +24,45 @@
 
 package org.graalvm.compiler.core.test;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.objectweb.asm.Opcodes;
 
+import sun.misc.Unsafe;
+
 public abstract class CustomizedBytecodePatternTest extends GraalCompilerTest implements Opcodes {
 
     protected Class<?> getClass(String className) throws ClassNotFoundException {
         return new CachedLoader(CustomizedBytecodePatternTest.class.getClassLoader(), className).findClass(className);
     }
 
+    /**
+     * @param className
+     * @param lookUp lookup object with boot class load capability (required for jdk 9 and above)
+     * @return loaded class
+     * @throws ClassNotFoundException
+     */
+    protected Class<?> getClassBL(String className, MethodHandles.Lookup lookUp) throws ClassNotFoundException {
+        byte[] gen = generateClass(className.replace('.', '/'));
+        Method defineClass = null;
+        Class<?> loadedClass = null;
+        try {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
+                defineClass = Unsafe.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
+                loadedClass = (Class<?>) defineClass.invoke(UNSAFE, className, gen, 0, gen.length, null, null);
+            } else {
+                defineClass = MethodHandles.lookup().getClass().getDeclaredMethod("defineClass", byte[].class);
+                loadedClass = (Class<?>) defineClass.invoke(lookUp, gen);
+            }
+        } catch (Exception e) {
+            throw new ClassNotFoundException();
+        }
+        return loadedClass;
+    }
+
     private class CachedLoader extends ClassLoader {
 
         final String className;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,11 +32,11 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.extended.MonitorExit;
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -67,7 +67,7 @@
         try (DebugContext.Scope s = debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
 
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -124,6 +124,7 @@
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
 import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.AddExports;
 import org.graalvm.compiler.test.GraalTest;
 import org.graalvm.compiler.test.JLModule;
@@ -150,9 +151,9 @@
 import jdk.vm.ci.meta.SpeculationLog;
 
 /**
- * Base class for Graal compiler unit tests.
+ * Base class for compiler unit tests.
  * <p>
- * White box tests for Graal compiler transformations use this pattern:
+ * White box tests for compiler transformations use this pattern:
  * <ol>
  * <li>Create a graph by {@linkplain #parseEager parsing} a method.</li>
  * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li>
@@ -194,7 +195,7 @@
      * as of JDK 9.
      */
     protected final void exportPackage(Class<?> moduleMember, String packageName) {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             JLModule.exportPackageTo(moduleMember, packageName, getClass());
         }
     }
@@ -224,27 +225,27 @@
      * Can be overridden by unit tests to verify properties of the graph.
      *
      * @param graph the graph at the end of HighTier
+     * @throws AssertionError if the verification fails
      */
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
-        return true;
+    protected void checkHighTierGraph(StructuredGraph graph) {
     }
 
     /**
      * Can be overridden by unit tests to verify properties of the graph.
      *
      * @param graph the graph at the end of MidTier
+     * @throws AssertionError if the verification fails
      */
-    protected boolean checkMidTierGraph(StructuredGraph graph) {
-        return true;
+    protected void checkMidTierGraph(StructuredGraph graph) {
     }
 
     /**
      * Can be overridden by unit tests to verify properties of the graph.
      *
      * @param graph the graph at the end of LowTier
+     * @throws AssertionError if the verification fails
      */
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
-        return true;
+    protected void checkLowTierGraph(StructuredGraph graph) {
     }
 
     protected static void breakpoint() {
@@ -288,7 +289,7 @@
 
             @Override
             protected void run(StructuredGraph graph) {
-                assert checkHighTierGraph(graph) : "failed HighTier graph check";
+                checkHighTierGraph(graph);
             }
 
             @Override
@@ -305,7 +306,7 @@
 
             @Override
             protected void run(StructuredGraph graph) {
-                assert checkMidTierGraph(graph) : "failed MidTier graph check";
+                checkMidTierGraph(graph);
             }
 
             @Override
@@ -322,7 +323,7 @@
 
             @Override
             protected void run(StructuredGraph graph) {
-                assert checkLowTierGraph(graph) : "failed LowTier graph check";
+                checkLowTierGraph(graph);
             }
 
             @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,8 +34,8 @@
 import org.graalvm.compiler.nodes.GraphEncoder;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -60,7 +60,7 @@
             if (javaMethod.hasBytecodes()) {
                 StructuredGraph originalGraph = parseEager(javaMethod, AllowAssumptions.YES);
                 if (canonicalize) {
-                    PhaseContext context = new PhaseContext(getProviders());
+                    CoreProviders context = getProviders();
                     new CanonicalizerPhase().apply(originalGraph, context);
                 }
                 originalGraphs.add(originalGraph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.core.test;
-
-import java.util.List;
-
-import org.graalvm.compiler.core.common.CompilationIdentifier;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.Invoke;
-import org.graalvm.compiler.nodes.InvokeNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.OpaqueNode;
-import org.graalvm.compiler.nodes.extended.LoadHubNode;
-import org.graalvm.compiler.nodes.extended.LoadMethodNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
-import org.graalvm.compiler.options.OptionValues;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-/**
- * Tests use of an intrinsic for virtual methods where the call site is indirect. A prime example is
- * an intrinsic for {@link Object#hashCode()}. The intrinsic can only be used if the call site would
- * actually dispatch to {@link Object#hashCode()} and not a method that overrides it.
- */
-public class GuardedIntrinsicTest extends GraalCompilerTest {
-
-    static class Super {
-        int getAge() {
-            return 11;
-        }
-    }
-
-    public static class Person extends Super {
-        int age;
-
-        public Person(int age) {
-            this.age = age;
-        }
-
-        @Override
-        public int getAge() {
-            return age;
-        }
-    }
-
-    @BytecodeParserForceInline
-    public static final Super createSuper() {
-        return new Super();
-    }
-
-    @BytecodeParserNeverInline
-    public static final Super createPerson() {
-        return new Person(42);
-    }
-
-    public static int getSuperAge(Super s) {
-        return s.getAge();
-    }
-
-    public static int getPersonAge(Person p) {
-        return p.getAge();
-    }
-
-    public static int makeSuperAge() {
-        return createSuper().getAge();
-    }
-
-    public static int makePersonAge() {
-        return createPerson().getAge();
-    }
-
-    @BeforeClass
-    public static void init() {
-        // Ensure classes are initialized
-        new Person(0).toString();
-    }
-
-    private StructuredGraph graph;
-    private StructuredGraph parsedForCompile;
-
-    @Override
-    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) {
-        graph = super.parseForCompile(method, compilationId, options);
-        parsedForCompile = (StructuredGraph) graph.copy(graph.getDebug());
-        return graph;
-    }
-
-    @Override
-    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
-        Registration r = new Registration(invocationPlugins, Super.class);
-
-        r.register1("getAge", Receiver.class, new InvocationPlugin() {
-            @Override
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                ConstantNode res = b.add(ConstantNode.forInt(new Super().getAge()));
-                b.add(new OpaqueNode(res));
-                b.push(JavaKind.Int, res);
-                return true;
-            }
-        });
-        super.registerInvocationPlugins(invocationPlugins);
-    }
-
-    public static int referenceMakeSuperAge() {
-        return 11;
-    }
-
-    public static int referenceMakePersonAge() {
-        return 42;
-    }
-
-    @Test
-    public void test01() {
-        Super inheritsHC = new Super();
-        Person overridesHC = new Person(0);
-
-        // Ensure the profile for getSuperAge includes both receiver types
-        getSuperAge(inheritsHC);
-        getSuperAge(overridesHC);
-
-        test("getSuperAge", inheritsHC);
-        test("getSuperAge", overridesHC);
-
-        // Check that the virtual dispatch test exists after bytecode parsing
-        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
-        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
-
-        // Check for the marker node indicating the intrinsic was applied
-        Assert.assertEquals(1, parsedForCompile.getNodes().filter(OpaqueNode.class).count());
-
-        // Final graph should have a single invoke
-        List<Node> invokes = graph.getNodes().filter(n -> n instanceof Invoke).snapshot();
-        Assert.assertEquals(invokes.toString(), 1, invokes.size());
-    }
-
-    @Test
-    public void test02() {
-        test("getPersonAge", new Person(0));
-
-        // Check that the virtual dispatch test does not exist after bytecode parsing
-        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
-        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
-
-        Assert.assertEquals(0, parsedForCompile.getNodes().filter(InvokeNode.class).count());
-    }
-
-    @Test
-    public void test03() {
-        test("makeSuperAge");
-
-        // Check that the virtual dispatch test does not exist after bytecode parsing
-        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
-        Assert.assertEquals(0, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
-
-        StructuredGraph referenceGraph = parseEager("referenceMakeSuperAge", AllowAssumptions.NO);
-        assertEquals(referenceGraph, graph, true, true);
-    }
-
-    @Test
-    public void test04() {
-        test("makePersonAge");
-
-        // Check that the virtual dispatch test exists after bytecode parsing
-        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadMethodNode.class).count());
-        Assert.assertEquals(1, parsedForCompile.getNodes().filter(LoadHubNode.class).count());
-
-        StructuredGraph referenceGraph = parseEager("referenceMakePersonAge", AllowAssumptions.NO);
-        assertEquals(referenceGraph, graph, true, true);
-    }
-
-    static final class ReadCacheEntry {
-
-        public final Object identity;
-        public final ValueNode object;
-
-        ReadCacheEntry(Object identity, ValueNode object) {
-            this.identity = identity;
-            this.object = object;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = ((identity == null) ? 0 : identity.hashCode());
-            return result + System.identityHashCode(object);
-        }
-    }
-
-    public static int getHashCode(ReadCacheEntry obj) {
-        return obj.hashCode();
-    }
-
-    @Test
-    public void test05() {
-        ReadCacheEntry val1 = new ReadCacheEntry("identity", ConstantNode.forBoolean(false));
-        ReadCacheEntry val2 = new ReadCacheEntry(Integer.valueOf(34), ConstantNode.forInt(42));
-        for (int i = 0; i < 10000; i++) {
-            getHashCode(val2);
-        }
-        test("getHashCode", val1);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,22 +24,14 @@
 
 package org.graalvm.compiler.core.test;
 
-import java.util.HashMap;
-import java.util.List;
-
 import org.graalvm.compiler.core.phases.HighTier;
 import org.graalvm.compiler.core.phases.MidTier;
 import org.graalvm.compiler.nodes.InvokeNode;
-import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.extended.LoadHubNode;
-import org.graalvm.compiler.nodes.extended.LoadMethodNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.compiler.test.SubprocessUtil;
 import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Test;
 
 public class HashCodeTest extends GraalCompilerTest {
@@ -81,10 +73,6 @@
         return System.identityHashCode(NonOverridingConstant);
     }
 
-    public static final int hashCodeNoFoldOverridingSnippet01(Object o) {
-        return o.hashCode();
-    }
-
     public static final int identityHashCodeFoldOverridingSnippet01() {
         return System.identityHashCode(OverridingConstant);
     }
@@ -117,56 +105,17 @@
 
     @Test
     public void test05() {
-        checkForGuardedIntrinsicPattern("hashCodeNoFoldOverridingSnippet01");
-
-        Object nullObject = null;
-        test("hashCodeNoFoldOverridingSnippet01", nullObject);
-        test("hashCodeNoFoldOverridingSnippet01", new Object());
-        test("hashCodeNoFoldOverridingSnippet01", new DontOverrideHashCode());
-    }
-
-    @Test
-    public void test06() {
         StructuredGraph g = buildGraphAfterMidTier("identityHashCodeFoldOverridingSnippet01");
         Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
     }
 
     @Test
-    public void test07() {
+    public void test06() {
         initialize(DontOverrideHashCode.class);
         StructuredGraph g = buildGraphAfterMidTier("dontOverrideHashCodeFinalClass");
         Assert.assertEquals(0, g.getNodes().filter(InvokeNode.class).count());
     }
 
-    public static final int hashCodeInterface(Appendable o) {
-        return o.hashCode();
-    }
-
-    @Test
-    public void test08() {
-        // This test requires profiling information which does not work reliable across platforms
-        // when running with -Xcomp
-        List<String> commandLine = SubprocessUtil.getVMCommandLine();
-        Assume.assumeTrue(commandLine != null);
-        Assume.assumeFalse(commandLine.contains("-Xcomp"));
-        initialize(Appendable.class);
-        checkForGuardedIntrinsicPattern("hashCodeInterface");
-
-        // Ensure the profile for the dispatch in hashCodeSnippet01
-        // has a receiver type that does not select Object.hashCode intrinsic
-        hashCodeSnippet01(new HashMap<>());
-        checkForGuardedIntrinsicPattern("hashCodeSnippet01");
-    }
-
-    private void checkForGuardedIntrinsicPattern(String name) {
-        StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
-        int invokeNodeCount = g.getNodes().filter(InvokeNode.class).count();
-        int invokeWithExceptionNodeCount = g.getNodes().filter(InvokeWithExceptionNode.class).count();
-        Assert.assertEquals(1, invokeNodeCount + invokeWithExceptionNodeCount);
-        Assert.assertEquals(1, g.getNodes().filter(LoadHubNode.class).count());
-        Assert.assertEquals(1, g.getNodes().filter(LoadMethodNode.class).count());
-    }
-
     @SuppressWarnings("try")
     private StructuredGraph buildGraphAfterMidTier(String name) {
         StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,6 +32,7 @@
 import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
@@ -39,7 +40,6 @@
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 /**
@@ -226,7 +226,7 @@
 
     private void testCombinedIf(String snippet, int count) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new FloatingReadPhase().apply(graph);
         MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
@@ -247,7 +247,7 @@
             }
         }
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) {
             fs.replaceFirstInput(param, null);
             param.safeDelete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,6 +31,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
@@ -38,7 +39,6 @@
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -71,7 +71,7 @@
         DebugContext debug = getDebugContext();
         try (DebugContext.Scope s = debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES, debug);
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerDivPowerOf2Test.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.RightShiftNode;
+import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
+import org.junit.Test;
+
+public class IntegerDivPowerOf2Test extends GraalCompilerTest {
+
+    public static int positiveDivByPowerOf2(boolean flag) {
+        int val = flag ? 1 : 10;
+        GraalDirectives.blackhole(val);
+        return val / 8;
+    }
+
+    @Test
+    public void testPositiveDivByPowerOf2() {
+        StructuredGraph graph = parseForCompile(getResolvedJavaMethod("positiveDivByPowerOf2"));
+        // We expect no rounding is needed
+        assertTrue(countShiftNode(graph) == 1);
+    }
+
+    private static int countShiftNode(StructuredGraph graph) {
+        return graph.getNodes().filter(node -> node instanceof RightShiftNode || node instanceof UnsignedRightShiftNode).count();
+    }
+
+    public static int unknownDivByPowerOf2(boolean flag) {
+        int val = flag ? 0x800000F0 : 0x20;
+        GraalDirectives.blackhole(val);
+        return val / 8;
+    }
+
+    @Test
+    public void testUnknownDivByPowerOf2() {
+        StructuredGraph graph = parseForCompile(getResolvedJavaMethod("unknownDivByPowerOf2"));
+        // We expect no rounding is needed
+        assertTrue(graph.getNodes().filter(RightShiftNode.class).count() <= 1);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,13 +24,11 @@
 
 package org.graalvm.compiler.core.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
 
 public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest {
 
@@ -168,7 +166,7 @@
 
     private StructuredGraph getCanonicalizedGraph(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) {
             state.replaceAtUsages(null);
             state.safeDelete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -36,7 +36,6 @@
 import org.graalvm.compiler.phases.common.LockEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Test;
 
@@ -70,7 +69,7 @@
         test("testSynchronizedSnippet", new A(), new A());
 
         StructuredGraph graph = getGraph("testSynchronizedSnippet", false);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -88,7 +87,7 @@
         test("testSynchronizedMethodSnippet", new A());
 
         StructuredGraph graph = getGraph("testSynchronizedMethodSnippet", false);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -106,7 +105,7 @@
     public void testUnrolledSync() {
         StructuredGraph graph = getGraph("testUnrolledSyncSnippet", false);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        canonicalizer.apply(graph, new PhaseContext(getProviders()));
+        canonicalizer.apply(graph, getProviders());
         HighTierContext context = getDefaultHighTierContext();
         new LoopFullUnrollPhase(canonicalizer, new DefaultLoopPolicies()).apply(graph, context);
         new LockEliminationPhase().apply(graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,8 +31,8 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class LoopFullUnrollTest extends GraalCompilerTest {
@@ -88,7 +88,7 @@
         try (DebugContext.Scope s = debug.scope(getClass().getSimpleName(), new DebugDumpScope(snippet))) {
             final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
 
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
 
             assertTrue(graph.getNodes().filter(LoopBeginNode.class).count() == loopCount);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class LoopUnswitchTest extends GraalCompilerTest {
@@ -134,8 +133,8 @@
         graph.clearAllStateAfter();
         referenceGraph.clearAllStateAfter();
 
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
+        new CanonicalizerPhase().apply(referenceGraph, getProviders());
         try (DebugContext.Scope s = debug.scope("Test", new DebugDumpScope("Test:" + snippet))) {
             assertEquals(referenceGraph, graph);
         } catch (Throwable e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,7 +32,6 @@
 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class MergeCanonicalizerTest extends GraalCompilerTest {
@@ -71,8 +70,8 @@
 
     private void testReturnCount(String snippet, int returnCount) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
+        new CanonicalizerPhase().apply(graph, getProviders());
         graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "Graph");
         assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,12 +33,12 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import org.graalvm.compiler.phases.contract.NodeCostUtil;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -318,12 +318,12 @@
         }
     }
 
-    private static class GraphCostPhase extends BasePhase<PhaseContext> {
+    private static class GraphCostPhase extends BasePhase<CoreProviders> {
         private double finalCycles;
         private double finalSize;
 
         @Override
-        protected void run(StructuredGraph graph, PhaseContext context) {
+        protected void run(StructuredGraph graph, CoreProviders context) {
             finalCycles = NodeCostUtil.computeGraphCycles(graph, true);
             finalSize = NodeCostUtil.computeGraphSize(graph);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/OptionsVerifierTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -49,7 +49,7 @@
 import org.graalvm.compiler.options.OptionDescriptors;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionsParser;
-import org.graalvm.compiler.test.GraalTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.junit.Test;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
@@ -82,7 +82,7 @@
 
         Classpath() throws IOException {
             List<String> names = new ArrayList<>(Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)));
-            if (GraalTest.Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
                 names.addAll(Arrays.asList(System.getProperty("sun.boot.class.path").split(File.pathSeparator)));
             } else {
                 names.addAll(Arrays.asList(System.getProperty("jdk.module.path").split(File.pathSeparator)));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,11 +33,11 @@
 import org.graalvm.compiler.nodes.calc.IsNullNode;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -103,7 +103,7 @@
 
     private StructuredGraph compileTestSnippet(final String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class PushThroughIfTest extends GraalCompilerTest {
@@ -66,15 +65,15 @@
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
+        new CanonicalizerPhase().apply(graph, getProviders());
 
         StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
         for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, getProviders());
         assertEquals(referenceGraph, graph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,11 +30,11 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -89,7 +89,7 @@
             // check shape of graph, with lots of assumptions. will probably fail if graph
             // structure changes significantly
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,14 +24,12 @@
 
 package org.graalvm.compiler.core.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
 
 public class ReassociateAndCanonicalTest extends GraalCompilerTest {
 
@@ -247,9 +245,9 @@
 
     private <T extends Node & IterableNodeType> void test(String test, String ref) {
         StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(testGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(testGraph, getProviders());
         StructuredGraph refGraph = parseEager(ref, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(refGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(refGraph, getProviders());
         assertEquals(testGraph, refGraph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -42,7 +42,7 @@
 public class ReferenceGetLoopTest extends GraalCompilerTest {
 
     @Override
-    protected boolean checkMidTierGraph(StructuredGraph graph) {
+    protected void checkMidTierGraph(StructuredGraph graph) {
         final LoopsData loops = new LoopsData(graph);
         boolean found = false;
         for (LoopEx loop : loops.loops()) {
@@ -62,7 +62,6 @@
         if (!found) {
             assertTrue(false, "Reference.referent not found in loop: " + getCanonicalGraphString(graph, true, false));
         }
-        return true;
     }
 
     public volatile Object referent;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,8 +27,8 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 /**
@@ -133,7 +133,7 @@
         // No debug scope to reduce console noise for @Test(expected = ...) tests
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         new CanonicalizerPhase().apply(graph, context);
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,6 +41,7 @@
 import org.graalvm.compiler.nodes.calc.AddNode;
 import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
 import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
@@ -50,7 +51,6 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class SchedulingTest2 extends GraphScheduleTest {
@@ -98,7 +98,7 @@
             }
         }
 
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
         MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,14 +24,12 @@
 
 package org.graalvm.compiler.core.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
 
 /**
  * This class tests some specific patterns the stamp system should be able to canonicalize away
@@ -113,7 +111,7 @@
 
     private void testZeroReturn(String methodName) {
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new DeadCodeEliminationPhase().apply(graph);
         assertConstantReturn(graph, 0);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class StraighteningTest extends GraalCompilerTest {
@@ -91,7 +90,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -188,14 +187,14 @@
          * tail-duplication gets activated thus resulting in a graph with more nodes than the
          * reference graph.
          */
-        new ConditionalEliminationPhase(false).apply(graph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new ConditionalEliminationPhase(false).apply(graph, getProviders());
+        new CanonicalizerPhase().apply(graph, getProviders());
         // a second canonicalizer is needed to process nested MaterializeNodes
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
-        new ConditionalEliminationPhase(false).apply(referenceGraph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new ConditionalEliminationPhase(false).apply(referenceGraph, getProviders());
+        new CanonicalizerPhase().apply(referenceGraph, getProviders());
+        new CanonicalizerPhase().apply(referenceGraph, getProviders());
         assertEquals(referenceGraph, graph);
     }
 
@@ -245,8 +244,8 @@
 
     private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
+        new CanonicalizerPhase().apply(graph, getProviders());
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph " + snippet);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,11 +30,11 @@
 import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Assert;
@@ -118,7 +118,7 @@
     }
 
     public void testEarlyReadElimination(StructuredGraph graph, int reads, int writes) {
-        PhaseContext context = getDefaultHighTierContext();
+        CoreProviders context = getDefaultHighTierContext();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         canonicalizer.apply(graph, context);
         new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
@@ -133,7 +133,7 @@
 
     public void testPartialEscapeReadElimination(StructuredGraph graph, int reads, int writes) {
         OptionValues options = graph.getOptions();
-        PhaseContext context = getDefaultHighTierContext();
+        CoreProviders context = getDefaultHighTierContext();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         canonicalizer.apply(graph, context);
         new PartialEscapePhase(true, true, canonicalizer, null, options).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,9 +28,9 @@
 
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Test;
 
@@ -146,7 +146,7 @@
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         OptionValues options = graph.getOptions();
-        PhaseContext context = getDefaultHighTierContext();
+        CoreProviders context = getDefaultHighTierContext();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         if (canonicalizeBefore) {
             canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.NewArrayNode;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 public class UnusedArray extends GraalCompilerTest {
@@ -67,7 +66,7 @@
 
     public void test(String method) {
         StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         NodeIterable<NewArrayNode> newArrayNodes = graph.getNodes().filter(NewArrayNode.class);
         assertThat(newArrayNodes, isEmpty());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,14 +29,14 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-public class VerifyBailoutUsage extends VerifyPhase<PhaseContext> {
+public class VerifyBailoutUsage extends VerifyPhase<CoreProviders> {
 
     private static final String[] AllowedPackagePrefixes;
 
@@ -73,7 +73,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         final ResolvedJavaType bailoutType = context.getMetaAccess().lookupJavaType(BailoutException.class);
         ResolvedJavaMethod caller = graph.method();
         String holderQualified = caller.format("%H");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBufferUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.core.test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.serviceprovider.BufferUtil;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * See {@link BufferUtil}.
+ */
+public class VerifyBufferUsage extends VerifyPhase<CoreProviders> {
+
+    private final Set<String> bufferTypes = new HashSet<>(Arrays.asList(
+                    "Ljava/nio/Buffer;",
+                    "Ljava/nio/ByteBuffer;",
+                    "Ljava/nio/ShortBuffer;",
+                    "Ljava/nio/CharBuffer;",
+                    "Ljava/nio/IntBuffer;",
+                    "Ljava/nio/LongBuffer;",
+                    "Ljava/nio/FloatBuffer;",
+                    "Ljava/nio/DoubleBuffer;",
+                    "Ljava/nio/MappedByteBuffer;"));
+
+    private final Set<String> bufferMethods = new HashSet<>(Arrays.asList(
+                    "position",
+                    "limit",
+                    "mark",
+                    "reset",
+                    "clear",
+                    "flip",
+                    "rewind"));
+
+    @Override
+    protected void verify(StructuredGraph graph, CoreProviders context) {
+        ResolvedJavaMethod caller = graph.method();
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            String calleeClassName = callee.getDeclaringClass().getName();
+            String calleeName = callee.getName();
+            if (bufferTypes.contains(calleeClassName) &&
+                            bufferMethods.contains(calleeName) &&
+                            !callee.getSignature().getReturnKind().isPrimitive()) {
+                StackTraceElement e = caller.asStackTraceElement(t.invoke().bci());
+                ResolvedJavaType receiverType = ((ObjectStamp) t.arguments().get(0).stamp(NodeView.DEFAULT)).type();
+                if (!receiverType.getName().equals("Ljava/nio/Buffer;")) {
+                    throw new VerificationError(
+                                    "%s: Cast receiver of type %s to java.nio.Buffer for call to %s to avoid problems with co-variant overloads added by https://bugs.openjdk.java.net/browse/JDK-4774077",
+                                    e, receiverType.toJavaName(),
+                                    callee.format("%H.%n(%p)"));
+                }
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyCallerSensitiveMethods.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyCallerSensitiveMethods.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,15 +24,14 @@
 
 package org.graalvm.compiler.core.test;
 
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
-
 import java.lang.annotation.Annotation;
 
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -40,7 +39,7 @@
 /**
  * Verifies a method is annotated with CallerSensitive iff it calls Reflection#getCallerClass().
  */
-public class VerifyCallerSensitiveMethods extends VerifyPhase<PhaseContext> {
+public class VerifyCallerSensitiveMethods extends VerifyPhase<CoreProviders> {
 
     Class<? extends Annotation> callerSensitiveClass;
     Class<?> reflectionClass;
@@ -54,7 +53,7 @@
     public VerifyCallerSensitiveMethods() {
         try {
             ClassLoader classLoader = ClassLoader.getSystemClassLoader();
-            if (Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
                 reflectionClass = classLoader.loadClass("sun.reflect.Reflection");
                 callerSensitiveClass = (Class<? extends Annotation>) classLoader.loadClass("sun.reflect.ConstantPool");
             } else {
@@ -67,7 +66,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         Invoke invoke = callsReflectionGetCallerClass(graph, context);
         Annotation annotation = graph.method().getAnnotation(callerSensitiveClass);
         if (invoke != null) {
@@ -81,7 +80,7 @@
         }
     }
 
-    private Invoke callsReflectionGetCallerClass(StructuredGraph graph, PhaseContext context) {
+    private Invoke callsReflectionGetCallerClass(StructuredGraph graph, CoreProviders context) {
         ResolvedJavaType reflectionType = context.getMetaAccess().lookupJavaType(reflectionClass);
         for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
             ResolvedJavaMethod callee = t.targetMethod();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -46,8 +46,8 @@
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.java.NewArrayNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -68,7 +68,7 @@
  * {@link DebugContext#log(String)} , {@link DebugContext#dump(int, Object, String)},
  * {@link DebugContext#logAndIndent(String)} and {@link DebugContext#verify(Object, String)}.
  */
-public class VerifyDebugUsage extends VerifyPhase<PhaseContext> {
+public class VerifyDebugUsage extends VerifyPhase<CoreProviders> {
 
     @Override
     public boolean checkContract() {
@@ -78,7 +78,7 @@
     MetaAccessProvider metaAccess;
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         metaAccess = context.getMetaAccess();
         ResolvedJavaType debugType = metaAccess.lookupJavaType(DebugContext.class);
         ResolvedJavaType nodeType = metaAccess.lookupJavaType(Node.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyFoldableMethods.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyFoldableMethods.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,8 +32,8 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -41,7 +41,7 @@
 /**
  * Verifies that all {@link Fold} annotated methods have at least one caller.
  */
-public class VerifyFoldableMethods extends VerifyPhase<PhaseContext> {
+public class VerifyFoldableMethods extends VerifyPhase<CoreProviders> {
 
     @Override
     public boolean checkContract() {
@@ -52,7 +52,7 @@
     ResolvedJavaType generatedInvocationPluginType;
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         ResolvedJavaMethod method = graph.method();
         if (method.getAnnotation(Fold.class) != null) {
             foldables.putIfAbsent(method, false);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGetOptionsUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGetOptionsUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,8 +31,8 @@
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -45,7 +45,7 @@
  * general but since there are several canonical methods with varying signatures this covers more
  * cases.
  */
-public class VerifyGetOptionsUsage extends VerifyPhase<PhaseContext> {
+public class VerifyGetOptionsUsage extends VerifyPhase<CoreProviders> {
     static Method lookupMethod(Class<?> klass, String name) {
         for (Method m : klass.getDeclaredMethods()) {
             if (m.getName().equals(name)) {
@@ -56,7 +56,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         MetaAccessProvider metaAccess = context.getMetaAccess();
         ResolvedJavaType canonicalizerToolClass = metaAccess.lookupJavaType(CanonicalizerTool.class);
         boolean hasTool = false;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGraphAddUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGraphAddUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,14 +41,14 @@
 import org.graalvm.compiler.nodes.ValueProxyNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-public class VerifyGraphAddUsage extends VerifyPhase<PhaseContext> {
+public class VerifyGraphAddUsage extends VerifyPhase<CoreProviders> {
     private static final Method ADD_OR_UNIQUE;
     private static final Method CONSTRUCTOR_NEW_INSTANCE;
     private static final EconomicSet<Class<?>> ALLOWED_CLASSES = EconomicSet.create();
@@ -66,7 +66,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         boolean allowed = false;
         for (Class<?> cls : ALLOWED_CLASSES) {
             ResolvedJavaType declaringClass = graph.method().getDeclaringClass();
@@ -87,7 +87,7 @@
         }
     }
 
-    private void checkNonFactory(StructuredGraph graph, EconomicSet<Node> seen, PhaseContext context, ValueNode node) {
+    private void checkNonFactory(StructuredGraph graph, EconomicSet<Node> seen, CoreProviders context, ValueNode node) {
         if (seen.contains(node)) {
             return;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyInstanceOfUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyInstanceOfUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,8 +29,8 @@
 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -39,7 +39,7 @@
 /**
  * Checks that we do not use {@code instanceof} for types where faster alternatives are available.
  */
-public class VerifyInstanceOfUsage extends VerifyPhase<PhaseContext> {
+public class VerifyInstanceOfUsage extends VerifyPhase<CoreProviders> {
 
     private static final Class<?>[] FORBIDDEN_INSTANCE_OF_CHECKS = {
                     MoveOp.class,
@@ -53,7 +53,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         final ResolvedJavaType[] bailoutType = new ResolvedJavaType[FORBIDDEN_INSTANCE_OF_CHECKS.length];
         for (int i = 0; i < FORBIDDEN_INSTANCE_OF_CHECKS.length; i++) {
             bailoutType[i] = context.getMetaAccess().lookupJavaType(FORBIDDEN_INSTANCE_OF_CHECKS[i]);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,8 +29,8 @@
 
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -43,7 +43,7 @@
  * can be modified by application code so {@link Services#getSavedProperties()} should be used
  * instead.
  */
-public class VerifySystemPropertyUsage extends VerifyPhase<PhaseContext> {
+public class VerifySystemPropertyUsage extends VerifyPhase<CoreProviders> {
 
     static final Class<?>[] BOXES = {Integer.class, Long.class, Boolean.class, Float.class, Double.class};
     static final int JVMCI_VERSION_MAJOR;
@@ -65,7 +65,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         MetaAccessProvider metaAccess = context.getMetaAccess();
         final ResolvedJavaType systemType = metaAccess.lookupJavaType(System.class);
         final ResolvedJavaType[] boxTypes = new ResolvedJavaType[BOXES.length];
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUnsafeAccess.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUnsafeAccess.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,8 +33,8 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -46,10 +46,10 @@
  * Checks that the {@link Unsafe} singleton instance is only accessed via well known classes such as
  * {@link GraalUnsafeAccess}.
  */
-public class VerifyUnsafeAccess extends VerifyPhase<PhaseContext> {
+public class VerifyUnsafeAccess extends VerifyPhase<CoreProviders> {
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         MetaAccessProvider metaAccess = context.getMetaAccess();
         final ResolvedJavaType unsafeType = metaAccess.lookupJavaType(Unsafe.class);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,8 +34,8 @@
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -45,7 +45,7 @@
  * Try to ensure that methods which update {@link Input} or {@link OptionalInput} fields also
  * include a call to {@link Node#updateUsages} or {@link Node#updateUsagesInterface}.
  */
-public class VerifyUpdateUsages extends VerifyPhase<PhaseContext> {
+public class VerifyUpdateUsages extends VerifyPhase<CoreProviders> {
 
     @Override
     public boolean checkContract() {
@@ -56,7 +56,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         if (graph.method().isConstructor()) {
             return;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUsageWithEquals.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUsageWithEquals.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,10 +32,10 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.JavaField;
 import jdk.vm.ci.meta.JavaKind;
@@ -51,7 +51,7 @@
  * checks the correct usage of the given type. Equality checks with == or != (except null checks)
  * results in an {@link AssertionError}.
  */
-public class VerifyUsageWithEquals extends VerifyPhase<PhaseContext> {
+public class VerifyUsageWithEquals extends VerifyPhase<CoreProviders> {
 
     @Override
     public boolean checkContract() {
@@ -143,7 +143,7 @@
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
             // bail out if we compare an object of type klass with == or != (except null checks)
             ResolvedJavaMethod method = graph.method();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableUsage.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableUsage.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,9 +34,9 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.Virtualizable;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -46,14 +46,14 @@
  * Implementors of {@link Virtualizable#virtualize(org.graalvm.compiler.nodes.spi.VirtualizerTool)}
  * must not apply effects on their {@link Graph graph} that cannot be easily undone.
  */
-public class VerifyVirtualizableUsage extends VerifyPhase<PhaseContext> {
+public class VerifyVirtualizableUsage extends VerifyPhase<CoreProviders> {
     @Override
     public boolean checkContract() {
         return false;
     }
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         final ResolvedJavaType graphType = context.getMetaAccess().lookupJavaType(Graph.class);
         final ResolvedJavaType virtualizableType = context.getMetaAccess().lookupJavaType(Virtualizable.class);
         final ResolvedJavaType constantNodeType = context.getMetaAccess().lookupJavaType(ConstantNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -63,7 +62,7 @@
     public void test1() {
         final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
         final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new DeadCodeEliminationPhase().apply(graph);
 
         for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/SynchronizedMethodDeoptimizationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,12 +24,12 @@
 
 package org.graalvm.compiler.core.test.deopt;
 
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.core.test.ea.EATestBase.TestClassObject;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.junit.Assume;
 import org.junit.Test;
 
-import org.graalvm.compiler.core.test.GraalCompilerTest;
-import org.graalvm.compiler.core.test.ea.EATestBase.TestClassObject;
-
 /**
  * In the following tests, we try to deoptimize out of synchronized methods.
  */
@@ -48,7 +48,7 @@
     @Test
     public void test1() {
         // https://bugs.openjdk.java.net/browse/JDK-8182755
-        Assume.assumeTrue(Java8OrEarlier);
+        Assume.assumeTrue(JavaVersionUtil.JAVA_SPEC <= 8);
 
         test("testMethodSynchronized", "test");
         test("testMethodSynchronized", (Object) null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,11 +33,11 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Test;
 
 /**
@@ -67,7 +67,7 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
             HighTierContext highTierContext = getDefaultHighTierContext();
             createInliningPhase().apply(graph, highTierContext);
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 
             // remove framestates in order to trigger the simplification.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
@@ -43,10 +44,8 @@
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
@@ -124,7 +123,7 @@
         }
     }
 
-    private long runAndTimePhase(StructuredGraph g, BasePhase<? super PhaseContext> phase) {
+    private long runAndTimePhase(StructuredGraph g, BasePhase<? super CoreProviders> phase) {
         HighTierContext context = getDefaultHighTierContext();
         long start = System.currentTimeMillis();
         phase.apply(g, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java	Fri Jun 28 14:36:42 2019 +0530
@@ -166,10 +166,11 @@
     /**
      * Creates the {@link DebugContext} to use when retrying a compilation.
      *
+     * @param initialDebug the debug context used in the failing compilation
      * @param options the options for configuring the debug context
      * @param logStream the log stream to use in the debug context
      */
-    protected abstract DebugContext createRetryDebugContext(OptionValues options, PrintStream logStream);
+    protected abstract DebugContext createRetryDebugContext(DebugContext initialDebug, OptionValues options, PrintStream logStream);
 
     @SuppressWarnings("try")
     public final T run(DebugContext initialDebug) {
@@ -277,7 +278,7 @@
 
                 ByteArrayOutputStream logBaos = new ByteArrayOutputStream();
                 PrintStream ps = new PrintStream(logBaos);
-                try (DebugContext retryDebug = createRetryDebugContext(retryOptions, ps)) {
+                try (DebugContext retryDebug = createRetryDebugContext(initialDebug, retryOptions, ps)) {
                     T res = performCompilation(retryDebug);
                     ps.println("There was no exception during retry.");
                     maybeExitVM(action);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,6 +28,7 @@
 import org.graalvm.compiler.options.EnumOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionStability;
 import org.graalvm.compiler.options.OptionType;
 
 /**
@@ -36,7 +37,7 @@
 public class GraalCompilerOptions {
 
     // @formatter:off
-    @Option(help = "Print an informational line to the console for each completed compilation.", type = OptionType.Debug)
+    @Option(help = "Print an informational line to the console for each completed compilation.", type = OptionType.Debug, stability = OptionStability.STABLE)
     public static final OptionKey<Boolean> PrintCompilation = new OptionKey<>(false);
     @Option(help = "Pattern for method(s) that will trigger an exception when compiled. " +
                    "This option exists to test handling compilation crashes gracefully. " +
@@ -44,9 +45,9 @@
                    "suffix will raise a bailout exception and a ':PermanentBailout' " +
                    "suffix will raise a permanent bailout exception.", type = OptionType.Debug)
     public static final OptionKey<String> CrashAt = new OptionKey<>(null);
-    @Option(help = "Treat compilation bailouts like compilation failures.", type = OptionType.User)
+    @Option(help = "Treat compilation bailouts like compilation failures.", type = OptionType.User, stability = OptionStability.STABLE)
     public static final OptionKey<Boolean> CompilationBailoutAsFailure = new OptionKey<>(false);
-    @Option(help = "file:doc-files/CompilationFailureActionHelp.txt", type = OptionType.User)
+    @Option(help = "file:doc-files/CompilationFailureActionHelp.txt", type = OptionType.User, stability = OptionStability.STABLE)
     public static final EnumOptionKey<ExceptionAction> CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Silent);
     @Option(help = "The maximum number of compilation failures to handle with the action specified " +
                    "by CompilationFailureAction before changing to a less verbose action. " +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalServiceThread.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.core;
+
+/**
+ * This is a utility class for Threads started by the compiler itself. In certain execution
+ * environments extra work must be done for these threads to execute correctly and this class
+ * provides hooks for this work.
+ */
+public class GraalServiceThread extends Thread {
+    private final Runnable runnable;
+
+    public GraalServiceThread(Runnable runnable) {
+        super();
+        this.runnable = runnable;
+    }
+
+    @Override
+    public final void run() {
+        beforeRun();
+        try {
+            runnable.run();
+        } finally {
+            afterRun();
+        }
+    }
+
+    /**
+     * Substituted by {@code com.oracle.svm.graal.hotspot.libgraal.
+     * Target_org_graalvm_compiler_truffle_common_TruffleCompilerRuntimeInstance} to attach to the
+     * peer runtime if required.
+     */
+    private void afterRun() {
+    }
+
+    /**
+     * Substituted by {@code com.oracle.svm.graal.hotspot.libgraal.
+     * Target_org_graalvm_compiler_truffle_common_TruffleCompilerRuntimeInstance} to attach to the
+     * peer runtime if required.
+     */
+    private void beforeRun() {
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRCompilerBackend.java	Fri Jun 28 14:36:42 2019 +0530
@@ -124,7 +124,11 @@
     }
 
     @SuppressWarnings("try")
-    private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites,
+    private static LIRGenerationResult emitLIR0(Backend backend,
+                    StructuredGraph graph,
+                    Object stub,
+                    RegisterConfig registerConfig,
+                    LIRSuites lirSuites,
                     String[] allocationRestrictedTo) {
         DebugContext debug = graph.getDebug();
         try (DebugContext.Scope ds = debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start(debug)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRGenerationProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/LIRGenerationProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,7 +44,10 @@
 public interface LIRGenerationProvider {
     LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes);
 
-    LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, RegisterConfig registerConfig, StructuredGraph graph,
+    LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId,
+                    LIR lir,
+                    RegisterConfig registerConfig,
+                    StructuredGraph graph,
                     Object stub);
 
     NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
@@ -52,7 +55,9 @@
     /**
      * Creates the object used to fill in the details of a given compilation result.
      */
-    CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult,
+    CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult,
+                    FrameMap frameMap,
+                    CompilationResult compilationResult,
                     CompilationResultBuilderFactory factory);
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -47,6 +47,6 @@
 
         appendPhase(new ExpandLogicPhase());
 
-        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 
 public class EconomyMidTier extends PhaseSuite<MidTierContext> {
@@ -53,5 +54,7 @@
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
 
         appendPhase(new FrameStateAssignmentPhase());
+
+        appendPhase(new WriteBarrierAdditionPhase());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,10 +32,10 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 /**
  * A utility phase for detecting when a phase would change the graph and reporting extra information
@@ -46,7 +46,7 @@
  *
  * @param <C>
  */
-public class GraphChangeMonitoringPhase<C extends PhaseContext> extends PhaseSuite<C> {
+public class GraphChangeMonitoringPhase<C extends CoreProviders> extends PhaseSuite<C> {
 
     private final String message;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,7 +25,6 @@
 package org.graalvm.compiler.core.phases;
 
 import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
-import static org.graalvm.compiler.core.common.GraalOptions.FullUnroll;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.core.common.GraalOptions.LoopPeeling;
 import static org.graalvm.compiler.core.common.GraalOptions.LoopUnswitch;
@@ -100,21 +99,17 @@
         }
 
         LoopPolicies loopPolicies = createLoopPolicies();
-        if (FullUnroll.getValue(options)) {
-            appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies));
-        }
+        appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies));
 
         if (OptLoopTransform.getValue(options)) {
             if (LoopPeeling.getValue(options)) {
-                appendPhase(new LoopPeelingPhase(loopPolicies));
+                appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopPeelingPhase(loopPolicies)));
             }
             if (LoopUnswitch.getValue(options)) {
-                appendPhase(new LoopUnswitchingPhase(loopPolicies));
+                appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopUnswitchingPhase(loopPolicies)));
             }
         }
 
-        appendPhase(canonicalizer);
-
         if (PartialEscapeAnalysis.getValue(options)) {
             appendPhase(new PartialEscapePhase(true, canonicalizer, options));
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -77,7 +77,8 @@
 
         appendPhase(new ExpandLogicPhase());
 
-        appendPhase(new FixReadsPhase(true, new SchedulePhase(GraalOptions.StressTestEarlyReads.getValue(options) ? SchedulingStrategy.EARLIEST : SchedulingStrategy.LATEST_OUT_OF_LOOPS)));
+        appendPhase(new FixReadsPhase(true,
+                        new SchedulePhase(GraalOptions.StressTestEarlyReads.getValue(options) ? SchedulingStrategy.EARLIEST : SchedulingStrategy.LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS)));
 
         appendPhase(canonicalizerWithoutGVN);
 
@@ -87,6 +88,6 @@
 
         appendPhase(new PropagateDeoptimizeProbabilityPhase());
 
-        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,9 +24,6 @@
 
 package org.graalvm.compiler.core.phases;
 
-import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.GuardTargets;
-import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.NonDeoptGuardTargets;
-import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks;
 import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.core.common.GraalOptions.OptDeoptimizationGrouping;
@@ -35,6 +32,9 @@
 import static org.graalvm.compiler.core.common.GraalOptions.PartialUnroll;
 import static org.graalvm.compiler.core.common.GraalOptions.ReassociateInvariants;
 import static org.graalvm.compiler.core.common.GraalOptions.VerifyHeapAtReturn;
+import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.GuardTargets;
+import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.NonDeoptGuardTargets;
+import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks;
 
 import org.graalvm.compiler.loop.DefaultLoopPolicies;
 import org.graalvm.compiler.loop.LoopPolicies;
@@ -56,6 +56,7 @@
 import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.VerifyHeapAtReturnPhase;
+import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 
 public class MidTier extends PhaseSuite<MidTierContext> {
@@ -109,6 +110,8 @@
         }
 
         appendPhase(canonicalizer);
+
+        appendPhase(new WriteBarrierAdditionPhase());
     }
 
     public LoopPolicies createLoopPolicies() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,11 +28,14 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 import jdk.internal.vm.compiler.collections.EconomicMap;
 import org.graalvm.compiler.options.EnumOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionStability;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.serviceprovider.GraalServices;
@@ -92,12 +95,12 @@
     @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
                    "See the Dump option for the pattern syntax.", type = OptionType.Debug)
     public static final OptionKey<String> Verify = new OptionKey<>(null);
-    @Option(help = "file:doc-files/DumpHelp.txt", type = OptionType.Debug)
+    @Option(help = "file:doc-files/DumpHelp.txt", type = OptionType.Debug, stability = OptionStability.STABLE)
     public static final OptionKey<String> Dump = new OptionKey<>(null);
     @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
                    "See the Dump option for the pattern syntax.", type = OptionType.Debug)
     public static final OptionKey<String> Log = new OptionKey<>(null);
-    @Option(help = "file:doc-files/MethodFilterHelp.txt")
+    @Option(help = "file:doc-files/MethodFilterHelp.txt", stability = OptionStability.STABLE)
     public static final OptionKey<String> MethodFilter = new OptionKey<>(null);
     @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug)
     public static final OptionKey<Boolean> MethodFilterRootOnly = new OptionKey<>(false);
@@ -119,7 +122,7 @@
     public static final OptionKey<String> MetricsThreadFilter = new OptionKey<>(null);
     @Option(help = "Enable debug output for stub code generation and snippet preparation.", type = OptionType.Debug)
     public static final OptionKey<Boolean> DebugStubsAndSnippets = new OptionKey<>(false);
-    @Option(help = "Send Graal compiler IR to dump handlers on error.", type = OptionType.Debug)
+    @Option(help = "Send compiler IR to dump handlers on error.", type = OptionType.Debug)
     public static final OptionKey<Boolean> DumpOnError = new OptionKey<>(false);
     @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
     public static final OptionKey<Boolean> InterceptBailout = new OptionKey<>(false);
@@ -203,7 +206,9 @@
         if (DumpPath.hasBeenSet(options)) {
             dumpDir = Paths.get(DumpPath.getValue(options));
         } else {
-            dumpDir = Paths.get(DumpPath.getValue(options), String.valueOf(GraalServices.getGlobalTimeStamp()));
+            Date date = new Date(GraalServices.getGlobalTimeStamp());
+            SimpleDateFormat formatter = new SimpleDateFormat( "YYYY.MM.dd.HH.mm.ss.SSS" );
+            dumpDir = Paths.get(DumpPath.getValue(options), formatter.format(date));
         }
         dumpDir = dumpDir.toAbsolutePath();
         if (!Files.exists(dumpDir)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TTY.java	Fri Jun 28 14:36:42 2019 +0530
@@ -118,6 +118,7 @@
 
     /**
      * The {@link PrintStream} to which all non-suppressed output from {@link TTY} is written.
+     * Substituted by {@code com.oracle.svm.graal.Target_org_graalvm_compiler_debug_TTY}.
      */
     public static final PrintStream out;
     static {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Fri Jun 28 14:36:42 2019 +0530
@@ -642,30 +642,6 @@
         }
 
         @Override
-        public void nodeAdded(Node node) {
-            head.event(NodeEvent.NODE_ADDED, node);
-            next.event(NodeEvent.NODE_ADDED, node);
-        }
-
-        @Override
-        public void inputChanged(Node node) {
-            head.event(NodeEvent.INPUT_CHANGED, node);
-            next.event(NodeEvent.INPUT_CHANGED, node);
-        }
-
-        @Override
-        public void usagesDroppedToZero(Node node) {
-            head.event(NodeEvent.ZERO_USAGES, node);
-            next.event(NodeEvent.ZERO_USAGES, node);
-        }
-
-        @Override
-        public void nodeRemoved(Node node) {
-            head.event(NodeEvent.NODE_REMOVED, node);
-            next.event(NodeEvent.NODE_REMOVED, node);
-        }
-
-        @Override
         public void changed(NodeEvent e, Node node) {
             head.event(e, node);
             next.event(e, node);
@@ -1151,7 +1127,7 @@
         nodesDeletedSinceLastCompression++;
 
         if (nodeEventListener != null) {
-            nodeEventListener.event(NodeEvent.NODE_ADDED, node);
+            nodeEventListener.event(NodeEvent.NODE_REMOVED, node);
         }
 
         // nodes aren't removed from the type cache here - they will be removed during iteration
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Fri Jun 28 14:36:42 2019 +0530
@@ -613,6 +613,7 @@
                 assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this);
                 newSuccessor.predecessor = this;
             }
+            maybeNotifyInputChanged(this);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.aarch64.AArch64AddressLoweringByUse;
 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
@@ -44,6 +43,7 @@
 import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGCProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
 import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
@@ -64,7 +64,6 @@
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.replacements.aarch64.AArch64GraphBuilderPlugins;
-import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 import org.graalvm.compiler.word.WordTypes;
 
@@ -83,7 +82,7 @@
 import jdk.vm.ci.runtime.JVMCIBackend;
 
 @ServiceProvider(HotSpotBackendFactory.class)
-public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
+public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
 
     @Override
     public String getName() {
@@ -112,6 +111,8 @@
         HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
         HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
         HotSpotLoweringProvider lowerer;
+        HotSpotStampProvider stampProvider;
+        HotSpotGCProvider gc;
         HotSpotSnippetReflectionProvider snippetReflection;
         HotSpotReplacementsImpl replacements;
         HotSpotSuitesProvider suites;
@@ -126,7 +127,7 @@
                 nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
             }
             try (InitTimer rt = timer("create WordTypes")) {
-                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+                wordTypes = createWordTypes(metaAccess, target);
             }
             try (InitTimer rt = timer("create ForeignCalls provider")) {
                 foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
@@ -134,17 +135,23 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
             }
-            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
+            try (InitTimer rt = timer("create stamp provider")) {
+                stampProvider = createStampProvider();
+            }
+            try (InitTimer rt = timer("create GC provider")) {
+                gc = createGCProvider(config);
+            }
+
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
             }
             try (InitTimer rt = timer("create Bytecode provider")) {
-                bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+                bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection);
             }
             try (InitTimer rt = timer("create Replacements provider")) {
-                replacements = createReplacements(p, snippetReflection, bytecodeProvider);
+                replacements = createReplacements(target, p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, graalRuntime.getOptions());
@@ -154,8 +161,7 @@
                 suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, replacements);
             }
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
-                            snippetReflection, wordTypes,
-                            plugins);
+                            snippetReflection, wordTypes, plugins, gc);
             replacements.setProviders(providers);
         }
         try (InitTimer rt = timer("instantiate backend")) {
@@ -180,10 +186,6 @@
         return new HotSpotRegisters(AArch64HotSpotRegisterConfig.threadRegister, AArch64HotSpotRegisterConfig.heapBaseRegister, sp);
     }
 
-    protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
-        return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget());
-    }
-
     protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess,
                     HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
         return new AArch64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
@@ -196,10 +198,6 @@
         return new AddressLoweringHotSpotSuitesProvider(suitesCreator, config, runtime, addressLoweringPhase);
     }
 
-    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
-        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
-    }
-
     protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
                     HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
         return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -71,7 +71,7 @@
     public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
         leaveFrame(crb, masm, /* emitSafepoint */false, false);
 
-        if (JavaVersionUtil.JAVA_SPECIFICATION_VERSION < 8) {
+        if (JavaVersionUtil.JAVA_SPEC < 8) {
             // Restore sp from fp if the exception PC is a method handle call site.
             try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayIndexOfStub.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayIndexOfStub.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,7 +24,6 @@
 
 package org.graalvm.compiler.hotspot.amd64;
 
-import jdk.vm.ci.meta.JavaKind;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
@@ -32,7 +31,6 @@
 import org.graalvm.compiler.hotspot.stubs.SnippetStub;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.amd64.AMD64ArrayIndexOfNode;
-import jdk.internal.vm.compiler.word.Pointer;
 
 public class AMD64ArrayIndexOfStub extends SnippetStub {
 
@@ -41,52 +39,77 @@
     }
 
     @Snippet
-    private static int indexOfTwoConsecutiveBytes(Pointer arrayPointer, int arrayLength, int searchValue) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, true, arrayPointer, arrayLength, searchValue);
+    private static int indexOfTwoConsecutiveBytes(byte[] array, int arrayLength, int fromIndex, int searchValue) {
+        return AMD64ArrayIndexOfNode.indexOf2ConsecutiveBytes(array, arrayLength, fromIndex, searchValue);
     }
 
     @Snippet
-    private static int indexOfTwoConsecutiveChars(Pointer arrayPointer, int arrayLength, int searchValue) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, true, arrayPointer, arrayLength, searchValue);
+    private static int indexOfTwoConsecutiveChars(char[] array, int arrayLength, int fromIndex, int searchValue) {
+        return AMD64ArrayIndexOfNode.indexOf2ConsecutiveChars(array, arrayLength, fromIndex, searchValue);
+    }
+
+    @Snippet
+    private static int indexOfTwoConsecutiveCharsCompact(byte[] array, int arrayLength, int fromIndex, int searchValue) {
+        return AMD64ArrayIndexOfNode.indexOf2ConsecutiveChars(array, arrayLength, fromIndex, searchValue);
     }
 
     @Snippet
-    private static int indexOf1Byte(Pointer arrayPointer, int arrayLength, byte b) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b);
+    private static int indexOf1Byte(byte[] array, int arrayLength, int fromIndex, byte b) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, b);
     }
 
     @Snippet
-    private static int indexOf2Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2);
+    private static int indexOf2Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, b1, b2);
     }
 
     @Snippet
-    private static int indexOf3Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2, b3);
+    private static int indexOf3Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2, byte b3) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, b1, b2, b3);
+    }
+
+    @Snippet
+    private static int indexOf4Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2, byte b3, byte b4) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, b1, b2, b3, b4);
     }
 
     @Snippet
-    private static int indexOf4Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3, byte b4) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2, b3, b4);
+    private static int indexOf1Char(char[] array, int arrayLength, int fromIndex, char c) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c);
     }
 
     @Snippet
-    private static int indexOf1Char(Pointer arrayPointer, int arrayLength, char c) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c);
+    private static int indexOf2Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2);
+    }
+
+    @Snippet
+    private static int indexOf3Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2, char c3) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2, c3);
+    }
+
+    @Snippet
+    private static int indexOf4Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2, char c3, char c4) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2, c3, c4);
     }
 
     @Snippet
-    private static int indexOf2Chars(Pointer arrayPointer, int arrayLength, char c1, char c2) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2);
+    private static int indexOf1CharCompact(byte[] array, int arrayLength, int fromIndex, char c) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c);
+    }
+
+    @Snippet
+    private static int indexOf2CharsCompact(byte[] array, int arrayLength, int fromIndex, char c1, char c2) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2);
     }
 
     @Snippet
-    private static int indexOf3Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2, c3);
+    private static int indexOf3CharsCompact(byte[] array, int arrayLength, int fromIndex, char c1, char c2, char c3) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2, c3);
     }
 
     @Snippet
-    private static int indexOf4Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4) {
-        return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2, c3, c4);
+    private static int indexOf4CharsCompact(byte[] array, int arrayLength, int fromIndex, char c1, char c2, char c3, char c4) {
+        return AMD64ArrayIndexOfNode.indexOf(array, arrayLength, fromIndex, c1, c2, c3, c4);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,12 +25,10 @@
 package org.graalvm.compiler.hotspot.amd64;
 
 import static jdk.vm.ci.common.InitTimer.timer;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.JAVA_SPECIFICATION_VERSION;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -40,6 +38,7 @@
 import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
 import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGCProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
 import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
@@ -58,7 +57,7 @@
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.replacements.amd64.AMD64GraphBuilderPlugins;
-import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 import org.graalvm.compiler.word.WordTypes;
 
@@ -76,7 +75,7 @@
 import jdk.vm.ci.runtime.JVMCIBackend;
 
 @ServiceProvider(HotSpotBackendFactory.class)
-public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
+public class AMD64HotSpotBackendFactory extends HotSpotBackendFactory {
 
     @Override
     public String getName() {
@@ -106,6 +105,8 @@
         HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
         ConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
         HotSpotLoweringProvider lowerer;
+        HotSpotStampProvider stampProvider;
+        HotSpotGCProvider gc;
         HotSpotSnippetReflectionProvider snippetReflection;
         HotSpotReplacementsImpl replacements;
         HotSpotSuitesProvider suites;
@@ -120,7 +121,7 @@
                 nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
             }
             try (InitTimer rt = timer("create WordTypes")) {
-                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+                wordTypes = createWordTypes(metaAccess, target);
             }
             try (InitTimer rt = timer("create ForeignCalls provider")) {
                 foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
@@ -128,17 +129,23 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
             }
-            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
+            try (InitTimer rt = timer("create stamp provider")) {
+                stampProvider = createStampProvider();
+            }
+            try (InitTimer rt = timer("create GC provider")) {
+                gc = createGCProvider(config);
+            }
+
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
 
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
             }
             try (InitTimer rt = timer("create Bytecode provider")) {
-                bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+                bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection);
             }
             try (InitTimer rt = timer("create Replacements provider")) {
-                replacements = createReplacements(p, snippetReflection, bytecodeProvider);
+                replacements = createReplacements(target, p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(compilerConfiguration, config, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, options);
@@ -148,8 +155,7 @@
                 suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, registers, replacements, options);
             }
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
-                            snippetReflection, wordTypes,
-                            plugins);
+                            snippetReflection, wordTypes, plugins, gc);
             replacements.setProviders(providers);
         }
         try (InitTimer rt = timer("instantiate backend")) {
@@ -161,7 +167,7 @@
                     HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess,
                     HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, OptionValues options) {
         Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements, options);
-        AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, false, JAVA_SPECIFICATION_VERSION >= 9, config.useFMAIntrinsics);
+        AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, false, JavaVersionUtil.JAVA_SPEC >= 9, config.useFMAIntrinsics);
         return plugins;
     }
 
@@ -173,10 +179,6 @@
         return new HotSpotRegisters(AMD64.r15, AMD64.r12, AMD64.rsp);
     }
 
-    protected HotSpotReplacementsImpl createReplacements(Providers p, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
-        return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, p.getCodeCache().getTarget());
-    }
-
     protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess,
                     HotSpotCodeCacheProvider codeCache, WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) {
         return new AMD64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
@@ -191,10 +193,6 @@
                         new AddressLoweringPhase(new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister(), options)));
     }
 
-    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
-        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
-    }
-
     protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
                     HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
         return new AMD64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -104,6 +104,8 @@
                         registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, LEAF, REEXECUTABLE, NO_LOCATIONS)));
         link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, options, providers,
                         registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS_COMPACT, options, providers,
+                        registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS_COMPACT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
         link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_1_BYTE, options, providers,
                         registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_1_BYTE, LEAF, REEXECUTABLE, NO_LOCATIONS)));
         link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_2_BYTES, options, providers,
@@ -120,6 +122,14 @@
                         registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_3_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
         link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS, options, providers,
                         registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_1_CHAR_COMPACT, options, providers,
+                        registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_1_CHAR_COMPACT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_2_CHARS_COMPACT, options, providers,
+                        registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_2_CHARS_COMPACT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_3_CHARS_COMPACT, options, providers,
+                        registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_3_CHARS_COMPACT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS_COMPACT, options, providers,
+                        registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS_COMPACT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
 
         link(new AMD64ArrayEqualsStub(AMD64ArrayEqualsStub.STUB_BOOLEAN_ARRAY_EQUALS, options, providers,
                         registerStubCall(AMD64ArrayEqualsStub.STUB_BOOLEAN_ARRAY_EQUALS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -71,7 +71,7 @@
         // Discard the return address, thus completing restoration of caller frame
         masm.incrementq(rsp, 8);
 
-        if (JavaVersionUtil.JAVA_SPECIFICATION_VERSION < 8) {
+        if (JavaVersionUtil.JAVA_SPEC < 8) {
             // Restore rsp from rbp if the exception PC is a method handle call site.
             AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset);
             masm.cmpl(dst, 0);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,7 +24,6 @@
 
 package org.graalvm.compiler.hotspot.amd64;
 
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
 
 import org.graalvm.compiler.api.replacements.Snippet;
@@ -43,6 +42,7 @@
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.amd64.AMD64ArrayIndexOfDispatchNode;
 import org.graalvm.compiler.replacements.amd64.AMD64ConvertSnippets;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
@@ -67,9 +67,12 @@
     @Override
     public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, GraalHotSpotVMConfig config) {
         convertSnippets = new AMD64ConvertSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
-        profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue(options) && !JavaVersionUtil.Java8OrEarlier && GeneratePIC.getValue(options)
-                        ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget())
-                        : null;
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
+            // AOT only introduced in JDK 9
+            profileSnippets = null;
+        } else {
+            profileSnippets = new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget());
+        }
         mathSnippets = new AMD64X87MathSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
         super.initialize(options, factories, providers, config);
     }
@@ -82,6 +85,8 @@
             profileSnippets.lower((ProfileNode) n, tool);
         } else if (n instanceof UnaryMathIntrinsicNode) {
             lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
+        } else if (n instanceof AMD64ArrayIndexOfDispatchNode) {
+            lowerArrayIndexOf((AMD64ArrayIndexOfDispatchNode) n);
         } else {
             super.lower(n, tool);
         }
@@ -125,6 +130,12 @@
         math.replaceAtUsages(call);
     }
 
+    private void lowerArrayIndexOf(AMD64ArrayIndexOfDispatchNode dispatchNode) {
+        StructuredGraph graph = dispatchNode.graph();
+        ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, dispatchNode.getStubCallDescriptor(), dispatchNode.getStubCallArgs()));
+        graph.replaceFixed(dispatchNode, call);
+    }
+
     @Override
     public Integer smallestCompareWidth() {
         return 8;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,7 +30,10 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.test.AddExports;
 import org.junit.Before;
 import org.junit.Test;
@@ -48,6 +51,8 @@
     @Before
     public void checkAMD64() {
         assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        assumeTrue("skipping FMA specific test", rt.getVMConfig().useFMAIntrinsics);
     }
 
     @Parameters(name = "{0}, {1}, {2}")
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,7 +30,10 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.test.AddExports;
 import org.junit.Before;
 import org.junit.Test;
@@ -48,6 +51,8 @@
     @Before
     public void checkAMD64() {
         assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+        HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
+        assumeTrue("skipping FMA specific tests", rt.getVMConfig().useFMAIntrinsics);
     }
 
     @Parameters(name = "{0}, {1}, {2}")
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/StringUTF16ToBytesGetCharsTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/StringUTF16ToBytesGetCharsTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,6 +32,7 @@
 import org.graalvm.compiler.nodes.java.NewArrayNode;
 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyCallNode;
 import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.AddExports;
 import org.junit.Test;
 
@@ -49,7 +50,7 @@
     private static final int N_OVERFLOW = 10;
 
     public StringUTF16ToBytesGetCharsTest() {
-        assumeFalse(Java8OrEarlier);
+        assumeFalse(JavaVersionUtil.JAVA_SPEC <= 8);
     }
 
     @Test
@@ -57,7 +58,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringUTF16");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "toBytes", char[].class, int.class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, NewArrayNode.class);
         assertInGraph(graph, ArrayCopyCallNode.class);
 
@@ -88,7 +89,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringUTF16");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, ArrayCopyCallNode.class);
 
         InstalledCode code = getCode(caller, graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/MitigateExceedingMaxOopMapStackOffsetTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.lir.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.jtt.LIRTest;
+import org.graalvm.compiler.lir.jtt.LIRTestSpecification;
+import org.graalvm.compiler.lir.stackslotalloc.LSStackSlotAllocator;
+import org.graalvm.compiler.nodes.SafepointNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.junit.Assume;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests the mitigation against overflowing the max size limit for a HotSpot OopMap. The mitigation
+ * works by {@link LSStackSlotAllocator} placing reference typed stack slots at lower offsets.
+ */
+public class MitigateExceedingMaxOopMapStackOffsetTest extends LIRTest {
+
+    /**
+     * Allocate stacks slots and initializes those at an odd index with a reference constant and
+     * those at an even index with a primitive constant.
+     */
+    private static class WriteStackValues extends LIRTestSpecification {
+        private final JavaConstant objectConstant;
+        private final JavaConstant primitiveConstant;
+
+        WriteStackValues(JavaConstant objectConstant, JavaConstant primitiveConstant) {
+            this.objectConstant = objectConstant;
+            this.primitiveConstant = primitiveConstant;
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+            LIRKind objectLirKind = LIRKind.reference(gen.target().arch.getPlatformKind(objectConstant.getJavaKind()));
+            LIRKind primitiveLirKind = LIRKind.value(gen.target().arch.getPlatformKind(primitiveConstant.getJavaKind()));
+
+            int numSlots = numPrimitiveSlots + numReferenceSlots;
+            List<AllocatableValue> slotList = new ArrayList<>(numSlots);
+            // Place reference slots at top and bottom of virtual frame
+            // with primitive slots in the middle. This tests that slot
+            // partitioning works.
+            for (int i = 0; i < numReferenceSlots / 2; i++) {
+                AllocatableValue src = gen.emitLoadConstant(objectLirKind, objectConstant);
+                VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(objectLirKind);
+                slotList.add(slot);
+                gen.emitMove(slot, src);
+            }
+            for (int i = 0; i < numPrimitiveSlots; i++) {
+                AllocatableValue src = gen.emitLoadConstant(objectLirKind, primitiveConstant);
+                VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(primitiveLirKind);
+                slotList.add(slot);
+                gen.emitMove(slot, src);
+            }
+            for (int i = numReferenceSlots / 2; i < numReferenceSlots; i++) {
+                AllocatableValue src = gen.emitLoadConstant(objectLirKind, objectConstant);
+                VirtualStackSlot slot = frameMapBuilder.allocateSpillSlot(objectLirKind);
+                slotList.add(slot);
+                gen.emitMove(slot, src);
+            }
+            slots = slotList.toArray(new AllocatableValue[slotList.size()]);
+        }
+    }
+
+    /**
+     * Read stacks slots and move their content into a blackhole.
+     */
+    private static class ReadStackValues extends LIRTestSpecification {
+
+        ReadStackValues() {
+        }
+
+        @Override
+        public void generate(LIRGeneratorTool gen) {
+            for (int i = 0; i < slots.length; i++) {
+                gen.emitBlackhole(gen.emitMove(slots[i]));
+            }
+        }
+    }
+
+    @Override
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
+        InvocationPlugin safepointPlugin = new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                b.add(new SafepointNode());
+                return true;
+            }
+        };
+        conf.getPlugins().getInvocationPlugins().register(safepointPlugin, getClass(), "safepoint");
+        return super.editGraphBuilderConfiguration(conf);
+    }
+
+    /*
+     * Safepoint Snippet
+     */
+    private static void safepoint() {
+    }
+
+    private static int numPrimitiveSlots;
+    private static int numReferenceSlots;
+    private static AllocatableValue[] slots;
+
+    private static final LIRTestSpecification readStackValues = new ReadStackValues();
+
+    @SuppressWarnings("unused")
+    @LIRIntrinsic
+    public static void instrinsic(LIRTestSpecification spec) {
+    }
+
+    private static final LIRTestSpecification writeStackValues = new WriteStackValues(JavaConstant.NULL_POINTER, JavaConstant.LONG_0);
+
+    public void testStackObjects() {
+        instrinsic(writeStackValues);
+        safepoint();
+        instrinsic(readStackValues);
+    }
+
+    @Test
+    public void runStackObjects() throws Throwable {
+        int max = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().maxOopMapStackOffset;
+        Assume.assumeFalse("no limit on oop map size", max == Integer.MAX_VALUE);
+        numPrimitiveSlots = (max / 8) * 2;
+        numReferenceSlots = (max / 8) - 100; // Should be enough margin for all platforms
+        runTest("testStackObjects");
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,7 @@
 import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
-import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGCProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
 import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
@@ -55,7 +55,6 @@
 import org.graalvm.compiler.phases.common.AddressLoweringPhase;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 import org.graalvm.compiler.replacements.sparc.SPARCGraphBuilderPlugins;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 
@@ -72,7 +71,7 @@
 import jdk.vm.ci.sparc.SPARC;
 
 @ServiceProvider(HotSpotBackendFactory.class)
-public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
+public class SPARCHotSpotBackendFactory extends HotSpotBackendFactory {
 
     @Override
     public String getName() {
@@ -95,22 +94,22 @@
         HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache();
         TargetDescription target = codeCache.getTarget();
         HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection();
-        HotSpotConstantFieldProvider constantFieldProvider = new HotSpotGraalConstantFieldProvider(config, metaAccess);
+        HotSpotConstantFieldProvider constantFieldProvider = createConstantFieldProvider(config, metaAccess);
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
-        HotSpotWordTypes wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+        HotSpotWordTypes wordTypes = createWordTypes(metaAccess, target);
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
-        HotSpotStampProvider stampProvider = new HotSpotStampProvider();
-        Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider);
-        HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
-        BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
-        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, target);
+        HotSpotStampProvider stampProvider = createStampProvider();
+        HotSpotGCProvider gc = createGCProvider(config);
+        Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, gc);
+        HotSpotSnippetReflectionProvider snippetReflection = createSnippetReflection(runtime, constantReflection, wordTypes);
+        BytecodeProvider bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection);
+        HotSpotReplacementsImpl replacements = createReplacements(target, p, snippetReflection, bytecodeProvider);
         Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, snippetReflection, replacements, wordTypes, runtime.getOptions());
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
-                        snippetReflection,
-                        wordTypes, plugins);
+                        snippetReflection, wordTypes, plugins, gc);
         replacements.setProviders(providers);
 
         return createBackend(config, runtime, providers);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BoxDeoptimizationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BoxDeoptimizationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -4,9 +4,7 @@
  *
  * 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
+ * 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
@@ -22,6 +20,8 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+
 package org.graalvm.compiler.hotspot.test;
 
 import org.graalvm.compiler.api.directives.GraalDirectives;
@@ -32,7 +32,7 @@
 import org.junit.Test;
 
 public class BoxDeoptimizationTest extends GraalCompilerTest {
-    private static boolean isJDK13OrLater = JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 13;
+    private static boolean isJDK13OrLater = JavaVersionUtil.JAVA_SPEC >= 13;
 
     public static void testInteger() {
         Object[] values = {42, new Exception()};
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32CSubstitutionsTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CRC32CSubstitutionsTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,22 +24,20 @@
 
 package org.graalvm.compiler.hotspot.test;
 
+import static org.junit.Assume.assumeFalse;
+
 import java.io.DataInputStream;
 import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.zip.Checksum;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-
-import org.graalvm.compiler.test.GraalTest;
-import org.graalvm.compiler.core.test.GraalCompilerTest;
+import java.nio.ByteBuffer;
+import java.util.zip.Checksum;
 
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.junit.Test;
 
-import static org.junit.Assume.assumeFalse;
-
 /**
  * Tests compiled calls to {@link java.util.zip.CRC32C}.
  */
@@ -56,7 +54,7 @@
 
     @Test
     public void test1() throws Throwable {
-        assumeFalse(GraalTest.Java8OrEarlier);
+        assumeFalse(JavaVersionUtil.JAVA_SPEC <= 8);
         String classfileName = CRC32CSubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class";
         InputStream s = CRC32CSubstitutionsTest.class.getResourceAsStream(classfileName);
         byte[] buf = new byte[s.available()];
@@ -79,7 +77,7 @@
 
     @Test
     public void test2() throws Throwable {
-        assumeFalse(GraalTest.Java8OrEarlier);
+        assumeFalse(JavaVersionUtil.JAVA_SPEC <= 8);
         String classfileName = CRC32CSubstitutionsTest.class.getSimpleName().replace('.', '/') + ".class";
         InputStream s = CRC32CSubstitutionsTest.class.getResourceAsStream(classfileName);
         byte[] buf = new byte[s.available()];
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Fri Jun 28 14:36:42 2019 +0530
@@ -386,6 +386,10 @@
         if (isJDK11OrHigher()) {
             // Relevant for Java flight recorder
             add(toBeInvestigated,
+                            "java/lang/CharacterDataLatin1.isDigit(I)Z",
+                            "java/lang/CharacterDataLatin1.isLowerCase(I)Z",
+                            "java/lang/CharacterDataLatin1.isUpperCase(I)Z",
+                            "java/lang/CharacterDataLatin1.isWhitespace(I)Z",
                             "jdk/jfr/internal/JVM.getEventWriter()Ljava/lang/Object;");
             if (!config.useBase64Intrinsics()) {
                 add(ignore,
@@ -393,14 +397,6 @@
             }
         }
 
-        if (isJDK12OrHigher()) {
-            add(toBeInvestigated,
-                            "java/lang/CharacterDataLatin1.isDigit(I)Z",
-                            "java/lang/CharacterDataLatin1.isLowerCase(I)Z",
-                            "java/lang/CharacterDataLatin1.isUpperCase(I)Z",
-                            "java/lang/CharacterDataLatin1.isWhitespace(I)Z");
-        }
-
         if (isJDK13OrHigher()) {
             add(toBeInvestigated,
                             "java/lang/Math.abs(I)I",
@@ -568,23 +564,23 @@
     }
 
     private static boolean isJDK9OrHigher() {
-        return JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 9;
+        return JavaVersionUtil.JAVA_SPEC >= 9;
     }
 
     private static boolean isJDK10OrHigher() {
-        return JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 10;
+        return JavaVersionUtil.JAVA_SPEC >= 10;
     }
 
     private static boolean isJDK11OrHigher() {
-        return JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 11;
+        return JavaVersionUtil.JAVA_SPEC >= 11;
     }
 
     private static boolean isJDK12OrHigher() {
-        return JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 12;
+        return JavaVersionUtil.JAVA_SPEC >= 12;
     }
 
     private static boolean isJDK13OrHigher() {
-        return JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 13;
+        return JavaVersionUtil.JAVA_SPEC >= 13;
     }
 
     public interface Refiner {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,7 +31,6 @@
 import static org.graalvm.compiler.core.test.ReflectionOptionDescriptors.extractEntries;
 import static org.graalvm.compiler.debug.MemUseTrackerKey.getCurrentThreadAllocatedBytes;
 import static org.graalvm.compiler.hotspot.test.CompileTheWorld.Options.DESCRIPTORS;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
 
 import java.io.ByteArrayOutputStream;
@@ -97,6 +96,7 @@
 import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import jdk.internal.vm.compiler.libgraal.LibGraal;
+import jdk.internal.vm.compiler.libgraal.LibGraalScope;
 import jdk.internal.vm.compiler.libgraal.OptionsEncoder;
 
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
@@ -117,9 +117,8 @@
 public final class CompileTheWorld {
 
     /**
-     * Magic token to denote that JDK classes are to be compiled. If
-     * {@link JavaVersionUtil#Java8OrEarlier}, then the classes in {@code rt.jar} are compiled.
-     * Otherwise the classes in the Java runtime image are compiled.
+     * Magic token to denote that JDK classes are to be compiled. For JDK 8, the classes in
+     * {@code rt.jar} are compiled. Otherwise the classes in the Java runtime image are compiled.
      */
     public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
 
@@ -398,7 +397,7 @@
         try (LibGraalParams libgraal = LibGraal.isAvailable() ? new LibGraalParams(compilerOptions) : null) {
             if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) {
                 String bcpEntry = null;
-                if (Java8OrEarlier) {
+                if (JavaVersionUtil.JAVA_SPEC <= 8) {
                     final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
                     for (int i = 0; i < entries.length && bcpEntry == null; i++) {
                         String entry = entries[i];
@@ -940,6 +939,7 @@
     /**
      * Compiles a method and gathers some statistics.
      */
+    @SuppressWarnings("try")
     private void compileMethod(HotSpotResolvedJavaMethod method, int counter, LibGraalParams libgraal) {
         try {
             long start = System.currentTimeMillis();
@@ -950,32 +950,33 @@
             HotSpotInstalledCode installedCode;
             if (libgraal != null) {
                 HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
-                long methodHandle = LibGraal.translate(runtime, method);
-                long isolateThread = LibGraal.getIsolateThread();
+                try (LibGraalScope scope = new LibGraalScope(runtime)) {
+                    long methodHandle = LibGraal.translate(runtime, method);
+                    long isolateThread = LibGraalScope.getIsolateThread();
 
-                StackTraceBuffer stackTraceBuffer = libgraal.getStackTraceBuffer();
+                    StackTraceBuffer stackTraceBuffer = libgraal.getStackTraceBuffer();
 
-                long stackTraceBufferAddress = stackTraceBuffer.getAddress();
-                long installedCodeHandle = compileMethodInLibgraal(isolateThread,
-                                methodHandle,
-                                useProfilingInfo,
-                                installAsDefault,
-                                libgraal.options.getAddress(),
-                                libgraal.options.size,
-                                libgraal.options.hash,
-                                stackTraceBufferAddress,
-                                stackTraceBuffer.size);
+                    long stackTraceBufferAddress = stackTraceBuffer.getAddress();
+                    long installedCodeHandle = compileMethodInLibgraal(isolateThread,
+                                    methodHandle,
+                                    useProfilingInfo,
+                                    installAsDefault,
+                                    libgraal.options.getAddress(),
+                                    libgraal.options.size,
+                                    libgraal.options.hash,
+                                    stackTraceBufferAddress,
+                                    stackTraceBuffer.size);
 
-                installedCode = LibGraal.unhand(runtime, HotSpotInstalledCode.class, installedCodeHandle);
-                if (installedCode == null) {
-                    int length = UNSAFE.getInt(stackTraceBufferAddress);
-                    byte[] data = new byte[length];
-                    UNSAFE.copyMemory(null, stackTraceBufferAddress + Integer.BYTES, data, ARRAY_BYTE_BASE_OFFSET, length);
-                    String stackTrace = new String(data).trim();
-                    println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
-                    println(stackTrace);
+                    installedCode = LibGraal.unhand(runtime, HotSpotInstalledCode.class, installedCodeHandle);
+                    if (installedCode == null) {
+                        int length = UNSAFE.getInt(stackTraceBufferAddress);
+                        byte[] data = new byte[length];
+                        UNSAFE.copyMemory(null, stackTraceBufferAddress + Integer.BYTES, data, ARRAY_BYTE_BASE_OFFSET, length);
+                        String stackTrace = new String(data).trim();
+                        println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
+                        println(stackTrace);
+                    }
                 }
-
             } else {
                 int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
                 HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.JLModule;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -75,8 +76,8 @@
     }
 
     private static Object getConstantPoolForObject() {
-        String miscPackage = Java8OrEarlier ? "sun.misc"
-                        : (Java11OrEarlier ? "jdk.internal.misc" : "jdk.internal.access");
+        String miscPackage = JavaVersionUtil.JAVA_SPEC <= 8 ? "sun.misc"
+                        : (JavaVersionUtil.JAVA_SPEC <= 11 ? "jdk.internal.misc" : "jdk.internal.access");
         try {
             Class<?> sharedSecretsClass = Class.forName(miscPackage + ".SharedSecrets");
             Class<?> javaLangAccessClass = Class.forName(miscPackage + ".JavaLangAccess");
@@ -111,11 +112,11 @@
      * This test uses some API hidden by the JDK9 module system.
      */
     private static void addExports(Class<?> c) {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             Object javaBaseModule = JLModule.fromClass(String.class);
             Object cModule = JLModule.fromClass(c);
             uncheckedAddExports(javaBaseModule, "jdk.internal.reflect", cModule);
-            if (Java11OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 11) {
                 uncheckedAddExports(javaBaseModule, "jdk.internal.misc", cModule);
             } else {
                 uncheckedAddExports(javaBaseModule, "jdk.internal.access", cModule);
@@ -222,7 +223,7 @@
             cw.visit(52, ACC_SUPER, PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", null, "java/lang/Object", null);
             cw.visitInnerClass(PACKAGE_NAME_INTERNAL + "/ConstantPoolTest", PACKAGE_NAME_INTERNAL + "/ConstantPoolSubstitutionsTests", "ConstantPoolTest",
                             ACC_STATIC);
-            String constantPool = Java8OrEarlier ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool";
+            String constantPool = JavaVersionUtil.JAVA_SPEC <= 8 ? "sun/reflect/ConstantPool" : "jdk/internal/reflect/ConstantPool";
 
             mv = cw.visitMethod(0, "<init>", "()V", null, null);
             mv.visitCode();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DeferredBarrierAdditionTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.GuardLoweringPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
+import org.graalvm.compiler.phases.common.inlining.InliningPhase;
+import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * This tests that barriers which are deferrable because of ReduceInitialCardMarks are properly
+ * omitted. The rule is simply that only writes to the very last allocated object can skip the card
+ * mark. By creating references between objects only one write can skip the card mark and the other
+ * must emit a card mark.
+ */
+public class DeferredBarrierAdditionTest extends HotSpotGraalCompilerTest {
+
+    private final GraalHotSpotVMConfig config = runtime().getVMConfig();
+
+    public static Object testCrossReferences() {
+        Object[] a = new Object[1];
+        Object[] b = new Object[1];
+        a[0] = b;
+        b[0] = a;
+        return a;
+    }
+
+    @Test
+    public void testGroupAllocation() throws Exception {
+        testHelper("testCrossReferences", 1, getInitialOptions());
+    }
+
+    @SuppressWarnings("try")
+    protected void testHelper(final String snippetName, final int expectedBarriers, OptionValues options) {
+        ResolvedJavaMethod snippet = getResolvedJavaMethod(snippetName);
+        DebugContext debug = getDebugContext(options, null, snippet);
+        try (DebugContext.Scope s = debug.scope("WriteBarrierAdditionTest", snippet)) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
+            HighTierContext highContext = getDefaultHighTierContext();
+            MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
+            new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
+            new CanonicalizerPhase().apply(graph, highContext);
+            new PartialEscapePhase(false, new CanonicalizerPhase(), debug.getOptions()).apply(graph, highContext);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
+            new GuardLoweringPhase().apply(graph, midContext);
+            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+            new WriteBarrierAdditionPhase().apply(graph, midContext);
+            debug.dump(DebugContext.BASIC_LEVEL, graph, "After Write Barrier Addition");
+
+            checkAssumptions(graph);
+
+            int barriers = 0;
+            if (config.useG1GC) {
+                barriers = graph.getNodes().filter(G1ReferentFieldReadBarrier.class).count() + graph.getNodes().filter(G1PreWriteBarrier.class).count() +
+                                graph.getNodes().filter(G1PostWriteBarrier.class).count();
+            } else {
+                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count();
+            }
+            if (expectedBarriers != barriers) {
+                Assert.assertEquals(getScheduledGraphString(graph), expectedBarriers, barriers);
+            }
+        } catch (Throwable e) {
+            throw debug.handle(e);
+        }
+    }
+
+    protected void checkAssumptions(StructuredGraph graph) {
+        assumeTrue(graph.getNodes().filter(AbstractNewObjectNode.class).isNotEmpty());
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
- * A Graal compiler test that needs access to the {@link HotSpotGraalRuntimeProvider}.
+ * A compiler test that needs access to the {@link HotSpotGraalRuntimeProvider}.
  */
 public abstract class HotSpotGraalCompilerTest extends GraalCompilerTest {
 
@@ -73,7 +73,7 @@
         HotSpotProviders providers = rt.getHostBackend().getProviders();
         CompilationIdentifier compilationId = runtime().getHostBackend().getCompilationIdentifier(method);
         OptionValues options = getInitialOptions();
-        StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, compilationId, getDebugContext(options));
+        StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, compilationId, getDebugContext(options), null);
         if (graph != null) {
             return getCode(method, graph, true, true, graph.getOptions());
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,12 +24,12 @@
 
 package org.graalvm.compiler.hotspot.test;
 
-import java.util.function.IntPredicate;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
 import java.security.PrivilegedAction;
+import java.util.function.IntPredicate;
+
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
 import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin;
@@ -37,22 +37,24 @@
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
-import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 import org.junit.Assert;
 import org.junit.Test;
 
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
 public class HotSpotInvokeDynamicPluginTest extends HotSpotGraalCompilerTest {
     @Override
     protected Plugins getDefaultGraphBuilderPlugins() {
@@ -94,7 +96,7 @@
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
         Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new GuardLoweringPhase().apply(graph, midTierContext);
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HsErrLogTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -39,6 +39,7 @@
 
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.SubprocessUtil;
 import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
 import org.junit.Assert;
@@ -54,7 +55,7 @@
     @Test
     public void test1() throws IOException, InterruptedException {
         List<String> args = new ArrayList<>();
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             args.add("-XX:-UseJVMCIClassLoader");
         }
         args.add("-XX:+UseJVMCICompiler");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -73,13 +73,12 @@
     }
 
     @Override
-    protected boolean checkLowTierGraph(StructuredGraph graph) {
+    protected void checkLowTierGraph(StructuredGraph graph) {
         for (ConstantNode constantNode : graph.getNodes().filter(ConstantNode.class)) {
             assert constantNode.asJavaConstant() == null || constantNode.asJavaConstant().getJavaKind() != JavaKind.Object ||
                             constantNode.asJavaConstant().isDefaultForKind() : "Found unexpected object constant " +
                                             constantNode + ", this should have been removed by the LoadJavaMirrorWithKlassPhase.";
         }
-        return true;
     }
 
     public static Class<?> classConstant() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectHashCodeInliningTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ObjectHashCodeInliningTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -42,7 +42,7 @@
     @Test
     public void testInstallCodeInvalidation() {
         for (int i = 0; i < 100000; i++) {
-            getHash(i % 1000 == 0 ? new Object() : "");
+            getHash(i % 10 == 0 ? new Object() : "");
         }
 
         ResolvedJavaMethod method = getResolvedJavaMethod("getHash");
@@ -74,8 +74,9 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
-        return containsForeignCallToIdentityHashCode(graph) && containsReadStringHash(graph);
+    protected void checkHighTierGraph(StructuredGraph graph) {
+        assert containsForeignCallToIdentityHashCode(graph) : "expected a foreign call to identity_hashcode";
+        assert containsReadStringHash(graph) : "expected a read from String.hash";
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Fri Jun 28 14:36:42 2019 +0530
@@ -72,7 +72,7 @@
                 if (plugin instanceof MethodSubstitutionPlugin) {
                     ResolvedJavaMethod method = CheckGraalIntrinsics.resolveIntrinsic(getMetaAccess(), intrinsic);
                     if (!method.isNative()) {
-                        StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, INVALID_COMPILATION_ID, debug);
+                        StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, INVALID_COMPILATION_ID, debug, null);
                         getCode(method, graph);
                     }
                 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,13 +32,12 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase;
-import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ReferentFieldReadBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
@@ -50,13 +49,12 @@
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
-import org.graalvm.compiler.word.Word;
-import jdk.internal.vm.compiler.word.WordFactory;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -257,34 +255,6 @@
         test2("testArrayCopy", src, dst, dst.length);
     }
 
-    public static class WordContainer {
-        public Word word;
-    }
-
-    public static void testWordFieldSnippet() {
-        WordContainer wordContainer = new WordContainer();
-        wordContainer.word = WordFactory.signed(42);
-    }
-
-    @Test
-    public void testWordField() throws Exception {
-        testHelper("testWordFieldSnippet", 0);
-    }
-
-    public static Word[] testWordArraySnippet(int length) {
-        Word fortyTwo = WordFactory.signed(42);
-        Word[] words = new Word[length];
-        for (int i = 0; i < length; i++) {
-            words[i] = fortyTwo;
-        }
-        return words;
-    }
-
-    @Test
-    public void testWordArray() throws Exception {
-        testHelper("testWordArraySnippet", 0);
-    }
-
     public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception {
         final int offset = (c == null ? 0 : ((Integer) c).intValue());
         final long displacement = (b == null ? 0 : ((Long) b).longValue());
@@ -311,7 +281,7 @@
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
             new GuardLoweringPhase().apply(graph, midContext);
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
-            new WriteBarrierAdditionPhase(config).apply(graph);
+            new WriteBarrierAdditionPhase().apply(graph, midContext);
             debug.dump(DebugContext.BASIC_LEVEL, graph, "After Write Barrier Addition");
 
             int barriers = 0;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,737 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.test;
-
-import java.util.List;
-
-import jdk.internal.vm.compiler.collections.EconomicMap;
-import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.debug.DebugContext.Scope;
-import org.graalvm.compiler.debug.DebugDumpScope;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialArrayRangeWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
-import org.graalvm.compiler.nodes.AbstractBeginNode;
-import org.graalvm.compiler.nodes.AbstractMergeNode;
-import org.graalvm.compiler.nodes.FieldLocationIdentity;
-import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.LoopBeginNode;
-import org.graalvm.compiler.nodes.LoopExitNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.GuardLoweringPhase;
-import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
-import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
-import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
-import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.MidTierContext;
-import jdk.internal.vm.compiler.word.LocationIdentity;
-import org.junit.Assert;
-import org.junit.Test;
-
-import jdk.vm.ci.meta.ResolvedJavaField;
-
-/**
- * The following tests validate the write barrier verification phase. For every tested snippet, an
- * array of write barrier indices and the total write barrier number are passed as parameters. The
- * indices denote the barriers that will be manually removed. The write barrier verification phase
- * runs after the write barrier removal and depending on the result an assertion might be generated.
- * The tests anticipate the presence or not of an assertion generated by the verification phase.
- */
-public class WriteBarrierVerificationTest extends HotSpotGraalCompilerTest {
-
-    public static int barrierIndex;
-
-    private final GraalHotSpotVMConfig config = runtime().getVMConfig();
-
-    public static class Container {
-
-        public Container a;
-        public Container b;
-    }
-
-    private static native void safepoint();
-
-    public static void test1Snippet(Container main) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        barrierIndex = 0;
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        safepoint();
-        barrierIndex = 2;
-        main.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test1() {
-        test("test1Snippet", 2, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test2() {
-        test("test1Snippet", 2, new int[]{2});
-    }
-
-    public static void test2Snippet(Container main) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        barrierIndex = 0;
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        barrierIndex = 2;
-        main.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test3() {
-        test("test2Snippet", 2, new int[]{1});
-    }
-
-    @Test
-    public void test4() {
-        test("test2Snippet", 2, new int[]{2});
-    }
-
-    public static void test3Snippet(Container main, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        barrierIndex = 0;
-        safepoint();
-        for (int i = 0; i < 10; i++) {
-            if (test) {
-                barrierIndex = 1;
-                main.a = temp1;
-                barrierIndex = 2;
-                main.b = temp2;
-            } else {
-                barrierIndex = 3;
-                main.a = temp1;
-                barrierIndex = 4;
-                main.b = temp2;
-            }
-        }
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test5() {
-        test("test3Snippet", 4, new int[]{1, 2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test6() {
-        test("test3Snippet", 4, new int[]{3, 4});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test7() {
-        test("test3Snippet", 4, new int[]{1});
-    }
-
-    @Test
-    public void test8() {
-        test("test3Snippet", 4, new int[]{2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test9() {
-        test("test3Snippet", 4, new int[]{3});
-    }
-
-    @Test
-    public void test10() {
-        test("test3Snippet", 4, new int[]{4});
-    }
-
-    public static void test4Snippet(Container main, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        for (int i = 0; i < 10; i++) {
-            if (test) {
-                barrierIndex = 2;
-                main.a = temp1;
-                barrierIndex = 3;
-                main.b = temp2;
-            } else {
-                barrierIndex = 4;
-                main.a = temp2;
-                barrierIndex = 5;
-                main.b = temp1;
-            }
-        }
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test11() {
-        test("test4Snippet", 5, new int[]{2, 3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test12() {
-        test("test4Snippet", 5, new int[]{4, 5});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test13() {
-        test("test4Snippet", 5, new int[]{1});
-    }
-
-    public static void test5Snippet(Container main) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        if (main.a == main.b) {
-            barrierIndex = 2;
-            main.a = temp1;
-            barrierIndex = 3;
-            main.b = temp2;
-        } else {
-            barrierIndex = 4;
-            main.a = temp2;
-            barrierIndex = 5;
-            main.b = temp1;
-        }
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test14() {
-        test("test5Snippet", 5, new int[]{1});
-    }
-
-    @Test
-    public void test15() {
-        test("test5Snippet", 5, new int[]{2});
-    }
-
-    @Test
-    public void test16() {
-        test("test5Snippet", 5, new int[]{4});
-    }
-
-    @Test
-    public void test17() {
-        test("test5Snippet", 5, new int[]{3});
-    }
-
-    @Test
-    public void test18() {
-        test("test5Snippet", 5, new int[]{5});
-    }
-
-    @Test
-    public void test19() {
-        test("test5Snippet", 5, new int[]{2, 3});
-    }
-
-    @Test
-    public void test20() {
-        test("test5Snippet", 5, new int[]{4, 5});
-    }
-
-    public static void test6Snippet(Container main, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        if (test) {
-            barrierIndex = 2;
-            main.a = temp1;
-            barrierIndex = 3;
-            main.b = temp1.a.a;
-        } else {
-            barrierIndex = 4;
-            main.a = temp2;
-            barrierIndex = 5;
-            main.b = temp2.a.a;
-        }
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test21() {
-        test("test6Snippet", 5, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test22() {
-        test("test6Snippet", 5, new int[]{1, 2});
-    }
-
-    @Test
-    public void test23() {
-        test("test6Snippet", 5, new int[]{3});
-    }
-
-    @Test
-    public void test24() {
-        test("test6Snippet", 5, new int[]{4});
-    }
-
-    public static void test7Snippet(Container main, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        barrierIndex = 1;
-        main.a = temp1;
-        if (test) {
-            barrierIndex = 2;
-            main.a = temp1;
-        }
-        barrierIndex = 3;
-        main.b = temp2;
-        safepoint();
-    }
-
-    @Test
-    public void test25() {
-        test("test7Snippet", 3, new int[]{2});
-    }
-
-    @Test
-    public void test26() {
-        test("test7Snippet", 3, new int[]{3});
-    }
-
-    @Test
-    public void test27() {
-        test("test7Snippet", 3, new int[]{2, 3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test28() {
-        test("test7Snippet", 3, new int[]{1});
-    }
-
-    public static void test8Snippet(Container main, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        if (test) {
-            barrierIndex = 1;
-            main.a = temp1;
-        }
-        barrierIndex = 2;
-        main.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test29() {
-        test("test8Snippet", 2, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test30() {
-        test("test8Snippet", 2, new int[]{2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test31() {
-        test("test8Snippet", 2, new int[]{1, 2});
-    }
-
-    public static void test9Snippet(Container main1, Container main2, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        if (test) {
-            barrierIndex = 1;
-            main1.a = temp1;
-        } else {
-            barrierIndex = 2;
-            main2.a = temp1;
-        }
-        barrierIndex = 3;
-        main1.b = temp2;
-        barrierIndex = 4;
-        main2.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test32() {
-        test("test9Snippet", 4, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test33() {
-        test("test9Snippet", 4, new int[]{2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test34() {
-        test("test9Snippet", 4, new int[]{3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test35() {
-        test("test9Snippet", 4, new int[]{4});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test36() {
-        test("test9Snippet", 4, new int[]{1, 2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test37() {
-        test("test9Snippet", 4, new int[]{3, 4});
-    }
-
-    public static void test10Snippet(Container main1, Container main2, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        if (test) {
-            barrierIndex = 1;
-            main1.a = temp1;
-            barrierIndex = 2;
-            main2.a = temp2;
-        } else {
-            barrierIndex = 3;
-            main2.a = temp1;
-        }
-        barrierIndex = 4;
-        main1.b = temp2;
-        barrierIndex = 5;
-        main2.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test38() {
-        test("test10Snippet", 5, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test39() {
-        test("test10Snippet", 5, new int[]{2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test40() {
-        test("test10Snippet", 5, new int[]{3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test41() {
-        test("test10Snippet", 5, new int[]{4});
-    }
-
-    @Test
-    public void test42() {
-        test("test10Snippet", 5, new int[]{5});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test43() {
-        test("test10Snippet", 5, new int[]{1, 2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test44() {
-        test("test10Snippet", 5, new int[]{1, 2, 3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test45() {
-        test("test10Snippet", 5, new int[]{3, 4});
-    }
-
-    public static void test11Snippet(Container main1, Container main2, Container main3, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        safepoint();
-        if (test) {
-            barrierIndex = 1;
-            main1.a = temp1;
-            barrierIndex = 2;
-            main3.a = temp1;
-            if (!test) {
-                barrierIndex = 3;
-                main2.a = temp2;
-            } else {
-                barrierIndex = 4;
-                main1.a = temp2;
-                barrierIndex = 5;
-                main3.a = temp2;
-            }
-        } else {
-            barrierIndex = 6;
-            main1.b = temp2;
-            for (int i = 0; i < 10; i++) {
-                barrierIndex = 7;
-                main3.a = temp1;
-            }
-            barrierIndex = 8;
-            main3.b = temp2;
-        }
-        barrierIndex = 9;
-        main1.b = temp2;
-        barrierIndex = 10;
-        main2.b = temp2;
-        barrierIndex = 11;
-        main3.b = temp2;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test46() {
-        test("test11Snippet", 11, new int[]{1});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test47() {
-        test("test11Snippet", 11, new int[]{2});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test48() {
-        test("test11Snippet", 11, new int[]{3});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test49() {
-        test("test11Snippet", 11, new int[]{6});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test50() {
-        test("test11Snippet", 11, new int[]{7});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test51() {
-        test("test11Snippet", 11, new int[]{8});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test52() {
-        test("test11Snippet", 11, new int[]{9});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test53() {
-        test("test11Snippet", 11, new int[]{10});
-    }
-
-    @Test
-    public void test54() {
-        test("test11Snippet", 11, new int[]{4});
-    }
-
-    @Test
-    public void test55() {
-        test("test11Snippet", 11, new int[]{5});
-    }
-
-    @Test
-    public void test56() {
-        test("test11Snippet", 11, new int[]{11});
-    }
-
-    public static void test12Snippet(Container main, Container main1, boolean test) {
-        Container temp1 = new Container();
-        Container temp2 = new Container();
-        barrierIndex = 0;
-        safepoint();
-        barrierIndex = 7;
-        main1.a = temp1;
-        for (int i = 0; i < 10; i++) {
-            if (test) {
-                barrierIndex = 1;
-                main.a = temp1;
-                barrierIndex = 2;
-                main.b = temp2;
-            } else {
-                barrierIndex = 3;
-                main.a = temp1;
-                barrierIndex = 4;
-                main.b = temp2;
-            }
-        }
-        barrierIndex = 5;
-        main.a = temp1;
-        barrierIndex = 6;
-        main.b = temp1;
-        barrierIndex = 8;
-        main1.b = temp1;
-        safepoint();
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test57() {
-        test("test12Snippet", 8, new int[]{5});
-    }
-
-    @Test
-    public void test58() {
-        test("test12Snippet", 8, new int[]{6});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test59() {
-        test("test12Snippet", 8, new int[]{7});
-    }
-
-    @Test(expected = AssertionError.class)
-    public void test60() {
-        test("test12Snippet", 8, new int[]{8});
-    }
-
-    public static void test13Snippet(Object[] a, Object[] b) {
-        System.arraycopy(a, 0, b, 0, a.length);
-    }
-
-    private interface GraphPredicate {
-        int apply(StructuredGraph graph);
-    }
-
-    private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) {
-        GraphPredicate noCheck = noArg -> expectedBarriers;
-        testPredicate(snippet, noCheck, removedBarrierIndices);
-    }
-
-    @SuppressWarnings("try")
-    private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) {
-        DebugContext debug = getDebugContext();
-        try (DebugCloseable d = debug.disableIntercept(); DebugContext.Scope s = debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) {
-            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES, debug);
-            HighTierContext highTierContext = getDefaultHighTierContext();
-            createInliningPhase().apply(graph, highTierContext);
-
-            MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
-
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
-            new GuardLoweringPhase().apply(graph, midTierContext);
-            new LoopSafepointInsertionPhase().apply(graph);
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, highTierContext);
-
-            new WriteBarrierAdditionPhase(config).apply(graph);
-
-            int barriers = 0;
-            // First, the total number of expected barriers is checked.
-            if (config.useG1GC) {
-                barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() +
-                                graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count();
-                Assert.assertTrue(expectedBarriers.apply(graph) * 2 == barriers);
-            } else {
-                barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count();
-                Assert.assertTrue(expectedBarriers.apply(graph) == barriers);
-            }
-            ResolvedJavaField barrierIndexField = getMetaAccess().lookupJavaField(WriteBarrierVerificationTest.class.getDeclaredField("barrierIndex"));
-            LocationIdentity barrierIdentity = new FieldLocationIdentity(barrierIndexField);
-            // Iterate over all write nodes and remove barriers according to input indices.
-            NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() {
-
-                @Override
-                protected Boolean processNode(FixedNode node, Boolean currentState) {
-                    if (node instanceof WriteNode) {
-                        WriteNode write = (WriteNode) node;
-                        LocationIdentity obj = write.getLocationIdentity();
-                        if (obj.equals(barrierIdentity)) {
-                            /*
-                             * A "barrierIndex" variable was found and is checked against the input
-                             * barrier array.
-                             */
-                            if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) {
-                                return true;
-                            }
-                        }
-                    } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) {
-                        // Remove flagged write barriers.
-                        if (currentState) {
-                            graph.removeFixed(((FixedWithNextNode) node));
-                            return false;
-                        }
-                    }
-                    return currentState;
-                }
-
-                private boolean eliminateBarrier(int index, int[] map) {
-                    for (int i = 0; i < map.length; i++) {
-                        if (map[i] == index) {
-                            return true;
-                        }
-                    }
-                    return false;
-                }
-
-                @Override
-                protected EconomicMap<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) {
-                    return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates;
-                }
-
-                @Override
-                protected Boolean merge(AbstractMergeNode merge, List<Boolean> states) {
-                    return false;
-                }
-
-                @Override
-                protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) {
-                    return false;
-                }
-            };
-
-            try (Scope disabled = debug.disable()) {
-                ReentrantNodeIterator.apply(closure, graph.start(), false);
-                new WriteBarrierVerificationPhase(config).apply(graph);
-            } catch (AssertionError error) {
-                /*
-                 * Catch assertion, test for expected one and re-throw in order to validate unit
-                 * test.
-                 */
-                Assert.assertTrue(error.getMessage().contains("Write barrier must be present"));
-                throw error;
-            }
-        } catch (Throwable e) {
-            throw debug.handle(e);
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,6 +32,8 @@
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
 
 import java.io.PrintStream;
+import java.util.Collections;
+import java.util.List;
 
 import jdk.internal.vm.compiler.collections.EconomicMap;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
@@ -42,7 +44,9 @@
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.DebugContext.Description;
 import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.TimerKey;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
@@ -85,9 +89,11 @@
         }
 
         @Override
-        protected DebugContext createRetryDebugContext(OptionValues retryOptions, PrintStream logStream) {
+        protected DebugContext createRetryDebugContext(DebugContext initialDebug, OptionValues retryOptions, PrintStream logStream) {
             SnippetReflectionProvider snippetReflection = compiler.getGraalRuntime().getHostProviders().getSnippetReflection();
-            return DebugContext.create(retryOptions, logStream, new GraalDebugHandlersFactory(snippetReflection));
+            Description description = initialDebug.getDescription();
+            List<DebugHandlersFactory> factories = Collections.singletonList(new GraalDebugHandlersFactory(snippetReflection));
+            return DebugContext.create(retryOptions, description, initialDebug.getGlobalMetrics(), logStream, factories);
         }
 
         @Override
@@ -183,11 +189,19 @@
 
     }
 
-    public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault) {
+    public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime,
+                    HotSpotGraalCompiler compiler,
+                    HotSpotCompilationRequest request,
+                    boolean useProfilingInfo,
+                    boolean installAsDefault) {
         this(jvmciRuntime, compiler, request, useProfilingInfo, false, installAsDefault);
     }
 
-    public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean shouldRetainLocalVariables,
+    public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime,
+                    HotSpotGraalCompiler compiler,
+                    HotSpotCompilationRequest request,
+                    boolean useProfilingInfo,
+                    boolean shouldRetainLocalVariables,
                     boolean installAsDefault) {
         this.jvmciRuntime = jvmciRuntime;
         this.compiler = compiler;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,6 +28,7 @@
 
 import java.util.Arrays;
 
+import org.graalvm.compiler.core.GraalServiceThread;
 import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -49,10 +50,10 @@
  * dog reports a long running compilation. Every
  * {@link Options#CompilationWatchDogStackTraceInterval} seconds after that point in time where the
  * same compilation is still executing, the watch dog takes a stack trace of the compiler thread. If
- * more than {@value Options#NonFatalIdenticalCompilationSnapshots} contiguous identical stack
- * traces are seen, the watch dog reports a stuck compilation and exits the VM.
+ * more than {@link Options#NonFatalIdenticalCompilationSnapshots} contiguous identical stack traces
+ * are seen, the watch dog reports a stuck compilation and exits the VM.
  */
-class CompilationWatchDog extends Thread implements AutoCloseable {
+class CompilationWatchDog implements Runnable, AutoCloseable {
 
     public static class Options {
         // @formatter:off
@@ -112,9 +113,6 @@
 
     CompilationWatchDog(Thread compilerThread, long startDelayMilliseconds, long stackTraceIntervalMilliseconds, int nonFatalIdenticalCompilationSnapshots) {
         this.compilerThread = compilerThread;
-        this.setName("WatchDog" + getId() + "[" + compilerThread.getName() + "]");
-        this.setPriority(Thread.MAX_PRIORITY);
-        this.setDaemon(true);
         this.startDelayMilliseconds = startDelayMilliseconds;
         this.stackTraceIntervalMilliseconds = stackTraceIntervalMilliseconds;
         this.nonFatalIdenticalCompilationSnapshots = nonFatalIdenticalCompilationSnapshots;
@@ -185,7 +183,7 @@
 
     @Override
     public String toString() {
-        return getName();
+        return "WatchDog[" + compilerThread.getName() + "]";
     }
 
     @Override
@@ -305,12 +303,16 @@
             // Lazily get a watch dog thread for the current compiler thread
             CompilationWatchDog watchDog = WATCH_DOGS.get();
             if (watchDog == null) {
-                Thread currentThread = currentThread();
+                Thread currentThread = Thread.currentThread();
                 long stackTraceIntervalMilliseconds = ms(Options.CompilationWatchDogStackTraceInterval.getValue(options));
                 int nonFatalIdenticalCompilationSnapshots = Options.NonFatalIdenticalCompilationSnapshots.getValue(options);
                 watchDog = new CompilationWatchDog(currentThread, startDelayMilliseconds, stackTraceIntervalMilliseconds, nonFatalIdenticalCompilationSnapshots);
                 WATCH_DOGS.set(watchDog);
-                watchDog.start();
+                GraalServiceThread thread = new GraalServiceThread(watchDog);
+                thread.setName(thread.getId() + " " + watchDog.toString());
+                thread.setPriority(Thread.MAX_PRIORITY);
+                thread.setDaemon(true);
+                thread.start();
             }
             watchDog.startCompilation(method, id);
             return watchDog;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.options.EnumOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionStability;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
@@ -53,9 +54,9 @@
 import jdk.vm.ci.common.InitTimer;
 
 /**
- * A factory that creates the {@link CompilerConfiguration} the Graal compiler will use. Each
- * factory must have a unique {@link #name} and {@link #autoSelectionPriority}. The latter imposes a
- * total ordering between factories for the purpose of auto-selecting the factory to use.
+ * A factory that creates the {@link CompilerConfiguration} the compiler will use. Each factory must
+ * have a unique {@link #name} and {@link #autoSelectionPriority}. The latter imposes a total
+ * ordering between factories for the purpose of auto-selecting the factory to use.
  */
 public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> {
 
@@ -67,11 +68,11 @@
 
     static class Options {
         // @formatter:off
-        @Option(help = "Names the Graal compiler configuration to use. If omitted, the compiler configuration " +
+        @Option(help = "Names the compiler configuration to use. If omitted, the compiler configuration " +
                        "with the highest auto-selection priority is used. To see the set of available configurations, " +
-                       "supply the value 'help' to this option.", type = OptionType.Expert)
+                       "supply the value 'help' to this option.", type = OptionType.Expert, stability = OptionStability.STABLE)
         public static final OptionKey<String> CompilerConfiguration = new OptionKey<>(null);
-        @Option(help = "Writes to the VM log information about the Graal compiler configuration selected.", type = OptionType.User)
+        @Option(help = "Writes to the VM log information about the compiler configuration selected.", type = OptionType.User, stability = OptionStability.STABLE)
         public static final OptionKey<ShowConfigurationLevel> ShowConfiguration = new EnumOptionKey<>(ShowConfigurationLevel.none);
         // @formatter:on
     }
@@ -195,7 +196,7 @@
         try (InitTimer t = timer("CompilerConfigurationFactory.selectFactory")) {
             String value = name == null ? Options.CompilerConfiguration.getValue(options) : name;
             if ("help".equals(value)) {
-                System.out.println("The available Graal compiler configurations are:");
+                System.out.println("The available compiler configurations are:");
                 for (CompilerConfigurationFactory candidate : getAllCandidates()) {
                     System.out.println("    " + candidate.name);
                 }
@@ -208,7 +209,7 @@
                     }
                 }
                 if (factory == null) {
-                    throw new GraalError("Graal compiler configuration '%s' not found. Available configurations are: %s", value,
+                    throw new GraalError("Compiler configuration '%s' not found. Available configurations are: %s", value,
                                     getAllCandidates().stream().map(c -> c.name).collect(Collectors.joining(", ")));
                 }
             } else {
@@ -247,7 +248,7 @@
 
     private static void printConfigInfo(CompilerConfigurationFactory factory) {
         URL location = factory.getClass().getResource(factory.getClass().getSimpleName() + ".class");
-        TTY.printf("Using Graal compiler configuration '%s' provided by %s loaded from %s%n", factory.name, factory.getClass().getName(), location);
+        TTY.printf("Using compiler configuration '%s' provided by %s loaded from %s%n", factory.name, factory.getClass().getName(), location);
     }
 
     private static <C> List<String> phaseNames(PhaseSuite<C> suite) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Jun 28 14:36:42 2019 +0530
@@ -97,7 +97,7 @@
     public static class Options {
         // @formatter:off
         @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible")
-        public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 9);
+        public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(JavaVersionUtil.JAVA_SPEC >= 9);
         @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
                         " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
         public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackendFactory.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,25 +24,64 @@
 
 package org.graalvm.compiler.hotspot;
 
+import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGCProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 
 import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+
+public abstract class HotSpotBackendFactory {
+
+    protected HotSpotGraalConstantFieldProvider createConstantFieldProvider(GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess) {
+        return new HotSpotGraalConstantFieldProvider(config, metaAccess);
+    }
+
+    protected HotSpotWordTypes createWordTypes(HotSpotMetaAccessProvider metaAccess, TargetDescription target) {
+        return new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+    }
 
-public interface HotSpotBackendFactory {
+    protected HotSpotStampProvider createStampProvider() {
+        return new HotSpotStampProvider();
+    }
+
+    protected HotSpotGCProvider createGCProvider(GraalHotSpotVMConfig config) {
+        return new HotSpotGCProvider(config);
+    }
+
+    protected HotSpotReplacementsImpl createReplacements(TargetDescription target, Providers p, HotSpotSnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
+        return new HotSpotReplacementsImpl(p, snippetReflection, bytecodeProvider, target);
+    }
+
+    protected ClassfileBytecodeProvider createBytecodeProvider(HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection) {
+        return new ClassfileBytecodeProvider(metaAccess, snippetReflection);
+    }
+
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, HotSpotWordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
+    }
 
     /**
      * Gets the name of this backend factory. This should not include the {@link #getArchitecture()
      * architecture}. The {@link CompilerConfigurationFactory} can select alternative backends based
      * on this name.
      */
-    String getName();
+    public abstract String getName();
 
     /**
      * Gets the class describing the architecture the backend created by this factory is associated
      * with.
      */
-    Class<? extends Architecture> getArchitecture();
+    public abstract Class<? extends Architecture> getArchitecture();
 
-    HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host);
+    public abstract HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Fri Jun 28 14:36:42 2019 +0530
@@ -48,6 +48,7 @@
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
 import org.graalvm.compiler.lir.phases.LIRSuites;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
@@ -74,7 +75,7 @@
 import jdk.vm.ci.runtime.JVMCICompiler;
 import sun.misc.Unsafe;
 
-public class HotSpotGraalCompiler implements GraalJVMCICompiler {
+public class HotSpotGraalCompiler implements GraalJVMCICompiler, Cancellable {
 
     private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
     private final HotSpotJVMCIRuntime jvmciRuntime;
@@ -86,7 +87,7 @@
     HotSpotGraalCompiler(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, OptionValues options) {
         this.jvmciRuntime = jvmciRuntime;
         this.graalRuntime = graalRuntime;
-        // It is sufficient to have one compilation counter object per Graal compiler object.
+        // It is sufficient to have one compilation counter object per compiler object.
         this.compilationCounters = Options.CompilationCountLimit.getValue(options) > 0 ? new CompilationCounters(options) : null;
         this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !DebugOptions.BootstrapInitializeOnly.getValue(options) ? BootstrapWatchDog.maybeCreate(graalRuntime) : null;
     }
@@ -111,7 +112,7 @@
     @SuppressWarnings("try")
     CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues initialOptions) {
         if (graalRuntime.isShutdown()) {
-            return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false);
+            return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), true);
         }
 
         ResolvedJavaMethod method = request.getMethod();
@@ -164,19 +165,31 @@
         return false;
     }
 
+    @Override
+    public boolean isCancelled() {
+        return graalRuntime.isShutdown();
+    }
+
     public StructuredGraph createGraph(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
         final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
-        StructuredGraph graph = method.isNative() || isOSR ? null : providers.getReplacements().getIntrinsicGraph(method, compilationId, debug);
+        StructuredGraph graph = method.isNative() || isOSR ? null : providers.getReplacements().getIntrinsicGraph(method, compilationId, debug, this);
 
         if (graph == null) {
             SpeculationLog speculationLog = method.getSpeculationLog();
             if (speculationLog != null) {
                 speculationLog.collectFailedSpeculations();
             }
-            graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.ifTrue(OptAssumptions.getValue(options))).method(method).entryBCI(entryBCI).speculationLog(
-                            speculationLog).useProfilingInfo(useProfilingInfo).compilationId(compilationId).build();
+            // @formatter:off
+            graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.ifTrue(OptAssumptions.getValue(options))).
+                            method(method).
+                            cancellable(this).
+                            entryBCI(entryBCI).
+                            speculationLog(speculationLog).
+                            useProfilingInfo(useProfilingInfo).
+                            compilationId(compilationId).build();
+            // @formatter:on
         }
         return graph;
     }
@@ -219,7 +232,11 @@
         return result;
     }
 
-    public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, boolean shouldRetainLocalVariables, CompilationIdentifier compilationId,
+    public CompilationResult compile(ResolvedJavaMethod method,
+                    int entryBCI,
+                    boolean useProfilingInfo,
+                    boolean shouldRetainLocalVariables,
+                    CompilationIdentifier compilationId,
                     DebugContext debug) {
         StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, debug.getOptions(), debug);
         CompilationResult result = new CompilationResult(compilationId);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Fri Jun 28 14:36:42 2019 +0530
@@ -129,8 +129,6 @@
      */
     private AtomicReference<OptionValues> optionsRef = new AtomicReference<>();
 
-    private final HotSpotGraalCompiler compiler;
-
     private final DiagnosticsOutputDirectory outputDirectory;
     private final Map<ExceptionAction, Integer> compilationProblemsPerAction;
 
@@ -161,7 +159,6 @@
         CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
         compilerConfigurationName = compilerConfigurationFactory.getName();
 
-        compiler = new HotSpotGraalCompiler(jvmciRuntime, this, options);
         if (IS_AOT) {
             management = null;
         } else {
@@ -367,7 +364,11 @@
     }
 
     private long runtimeStartTime;
-    private boolean shutdown;
+
+    /**
+     * Called from compiler threads to check whether to bail out of a compilation.
+     */
+    private volatile boolean shutdown;
 
     /**
      * Take action related to entering a new execution phase.
@@ -394,6 +395,16 @@
         BenchmarkCounters.shutdown(runtime(), optionsRef.get(), runtimeStartTime);
 
         outputDirectory.close();
+
+        shutdownLibGraal();
+    }
+
+    /**
+     * Substituted by
+     * {@code com.oracle.svm.graal.hotspot.libgraal.Target_org_graalvm_compiler_hotspot_HotSpotGraalRuntime}
+     * to call {@code org.graalvm.nativeimage.VMRuntime.shutdown()}.
+     */
+    private static void shutdownLibGraal() {
     }
 
     void clearMetrics() {
@@ -580,6 +591,7 @@
         extra.put(DebugOptions.PrintGraphHost, host);
         extra.put(DebugOptions.PrintGraphPort, port);
         OptionValues compileOptions = new OptionValues(getOptions(), extra);
+        HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime().getCompiler();
         compiler.compileMethod(new HotSpotCompilationRequest(hotSpotMethod, -1, 0L), false, compileOptions);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalServices.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot;
+
+import jdk.vm.ci.hotspot.HotSpotMetaData;
+
+public class HotSpotGraalServices {
+
+    /**
+     * Get the implicit exceptions section of a {@code HotSpotMetaData} if it exists.
+     */
+    @SuppressWarnings("unused")
+    public static byte[] getImplicitExceptionBytes(HotSpotMetaData metaData) {
+        return metaData.implicitExceptionBytes();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,6 +41,7 @@
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.hotspot.meta.HotSpotWordOperationPlugin;
 import org.graalvm.compiler.hotspot.word.HotSpotOperation;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -91,7 +92,7 @@
     }
 
     @Override
-    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) {
+    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug, Cancellable cancellable) {
         boolean useEncodedGraphs = UseEncodedGraphs.getValue(debug.getOptions());
         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
             HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
@@ -101,13 +102,13 @@
                 if (useEncodedGraphs) {
                     replacements.registerMethodSubstitution(msp, method, ROOT_COMPILATION, debug.getOptions());
                 }
-                StructuredGraph methodSubstitution = replacements.getMethodSubstitution(msp, method, ROOT_COMPILATION, StructuredGraph.AllowAssumptions.YES, debug.getOptions());
+                StructuredGraph methodSubstitution = replacements.getMethodSubstitution(msp, method, ROOT_COMPILATION, StructuredGraph.AllowAssumptions.YES, cancellable, debug.getOptions());
                 methodSubstitution.resetDebug(debug);
                 return methodSubstitution;
             }
             return null;
         }
-        return super.getIntrinsicGraph(method, compilationId, debug);
+        return super.getIntrinsicGraph(method, compilationId, debug, cancellable);
     }
 
     @Override
@@ -122,7 +123,7 @@
                 }
                 // This assumes the normal path creates the graph using
                 // GraphBuilderConfiguration.getSnippetDefault with omits exception edges
-                StructuredGraph subst = getMethodSubstitution(msPlugin, targetMethod, INLINE_AFTER_PARSING, StructuredGraph.AllowAssumptions.NO, options);
+                StructuredGraph subst = getMethodSubstitution(msPlugin, targetMethod, INLINE_AFTER_PARSING, StructuredGraph.AllowAssumptions.NO, null, options);
                 return subst;
             }
         }
@@ -232,7 +233,7 @@
 
     @Override
     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
-                    StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
+                    StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
         boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
             if (!IS_IN_NATIVE_IMAGE) {
@@ -242,7 +243,7 @@
             if (getEncodedSnippets() == null) {
                 throw GraalError.shouldNotReachHere("encoded snippets not found");
             }
-            return getEncodedSnippets().getMethodSubstitutionGraph(plugin, original, this, context, allowAssumptions, options);
+            return getEncodedSnippets().getMethodSubstitutionGraph(plugin, original, this, context, allowAssumptions, cancellable, options);
         }
         return null;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -39,7 +39,6 @@
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
-import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.serviceprovider.GraalServices;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 
@@ -60,7 +59,7 @@
 
     @Override
     public PrintStream getStream() {
-        return Options.LogFile.getStream(defaultOptions());
+        return Options.LogFile.getStream();
     }
 
     /**
@@ -96,22 +95,57 @@
          * operation is performed on the stream. This is required to break a deadlock in early JVMCI
          * initialization.
          */
-        static class DelayedOutputStream extends OutputStream {
+        class DelayedOutputStream extends OutputStream {
             private volatile OutputStream lazy;
 
             private OutputStream lazy() {
                 if (lazy == null) {
                     synchronized (this) {
                         if (lazy == null) {
+                            String nameTemplate = LogStreamOptionKey.this.getValue(defaultOptions());
+                            if (nameTemplate != null) {
+                                String name = makeFilename(nameTemplate);
+                                try {
+                                    final boolean enableAutoflush = true;
+                                    FileOutputStream result = new FileOutputStream(name);
+                                    if (!Services.IS_IN_NATIVE_IMAGE) {
+                                        printVMConfig(enableAutoflush, result);
+                                    } else {
+                                        // There are no VM arguments for the libgraal library.
+                                    }
+                                    lazy = result;
+                                    return lazy;
+                                } catch (FileNotFoundException e) {
+                                    throw new RuntimeException("couldn't open file: " + name, e);
+                                }
+                            }
+
                             lazy = HotSpotJVMCIRuntime.runtime().getLogStream();
                             PrintStream ps = new PrintStream(lazy);
                             ps.printf("[Use -D%sLogFile=<path> to redirect Graal log output to a file.]%n", GRAAL_OPTION_PROPERTY_PREFIX);
+                            ps.flush();
                         }
                     }
                 }
                 return lazy;
             }
 
+            @SuppressFBWarnings(value = "DLS_DEAD_LOCAL_STORE", justification = "false positive on dead store to `ps`")
+            private void printVMConfig(final boolean enableAutoflush, FileOutputStream result) {
+                /*
+                 * Add the JVM and Java arguments to the log file to help identity it.
+                 */
+                PrintStream ps = new PrintStream(result, enableAutoflush);
+                List<String> inputArguments = GraalServices.getInputArguments();
+                if (inputArguments != null) {
+                    ps.println("VM Arguments: " + String.join(" ", inputArguments));
+                }
+                String cmd = Services.getSavedProperties().get("sun.java.command");
+                if (cmd != null) {
+                    ps.println("sun.java.command=" + cmd);
+                }
+            }
+
             @Override
             public void write(byte[] b, int off, int len) throws IOException {
                 lazy().write(b, off, len);
@@ -137,32 +171,8 @@
          * Gets the print stream configured by this option. If no file is configured, the print
          * stream will output to HotSpot's {@link HotSpotJVMCIRuntime#getLogStream() log} stream.
          */
-        @SuppressFBWarnings(value = "DLS_DEAD_LOCAL_STORE", justification = "false positive on dead store to `ps`")
-        public PrintStream getStream(OptionValues options) {
-            String nameTemplate = getValue(options);
-            if (nameTemplate != null) {
-                String name = makeFilename(nameTemplate);
-                try {
-                    final boolean enableAutoflush = true;
-                    PrintStream ps = new PrintStream(new FileOutputStream(name), enableAutoflush);
-                    /*
-                     * Add the JVM and Java arguments to the log file to help identity it.
-                     */
-                    List<String> inputArguments = GraalServices.getInputArguments();
-                    if (inputArguments != null) {
-                        ps.println("VM Arguments: " + String.join(" ", inputArguments));
-                    }
-                    String cmd = Services.getSavedProperties().get("sun.java.command");
-                    if (cmd != null) {
-                        ps.println("sun.java.command=" + cmd);
-                    }
-                    return ps;
-                } catch (FileNotFoundException e) {
-                    throw new RuntimeException("couldn't open file: " + name, e);
-                }
-            } else {
-                return new PrintStream(new DelayedOutputStream());
-            }
+        public PrintStream getStream() {
+            return new PrintStream(new DelayedOutputStream());
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,9 +41,8 @@
  */
 public final class JVMCIVersionCheck {
 
-    // 0.57 introduces HotSpotJVMCIRuntime.excludeFromJVMCICompilation
-    private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
-    private static final int JVMCI8_MIN_MINOR_VERSION = 57;
+    private static final int JVMCI8_MIN_MAJOR_VERSION = 19;
+    private static final int JVMCI8_MIN_MINOR_VERSION = 1;
 
     private static void failVersionCheck(Map<String, String> props, boolean exit, String reason, Object... args) {
         Formatter errorMessage = new Formatter().format(reason, args);
@@ -55,7 +54,7 @@
         errorMessage.format("Currently used VM configuration is: %s%n", vmName);
         if (props.get("java.specification.version").compareTo("1.9") < 0) {
             errorMessage.format("Download the latest JVMCI JDK 8 from " +
-                            "http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html or " +
+                            "https://www.oracle.com/technetwork/graalvm/downloads/index.html or " +
                             "https://github.com/graalvm/openjdk8-jvmci-builder/releases");
         } else {
             errorMessage.format("Download JDK 11 or later.");
@@ -156,6 +155,14 @@
         return false;
     }
 
+    private static String getJVMCIVersionString(int major, int minor) {
+        if (major >= 19) {
+            return String.format("%d-b%02d", major, minor);
+        } else {
+            return String.format("%d.%d", major, minor);
+        }
+    }
+
     private void run(boolean exitOnFailure, int jvmci8MinMajorVersion, int jvmci8MinMinorVersion) {
         // Don't use regular expressions to minimize Graal startup time
         if (javaSpecVersion.compareTo("1.9") < 0) {
@@ -180,8 +187,8 @@
                     if (major > jvmci8MinMajorVersion || (major >= jvmci8MinMajorVersion && minor >= jvmci8MinMinorVersion)) {
                         return;
                     }
-                    failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
-                                    major, minor, jvmci8MinMajorVersion, jvmci8MinMinorVersion);
+                    failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %s < %s.%n",
+                                    getJVMCIVersionString(major, minor), getJVMCIVersionString(jvmci8MinMajorVersion, jvmci8MinMinorVersion));
                     return;
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,6 +66,7 @@
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.EncodedGraph;
 import org.graalvm.compiler.nodes.FrameState;
@@ -109,7 +110,6 @@
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MemoryAccessProvider;
 import jdk.vm.ci.meta.MethodHandleAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
@@ -283,24 +283,30 @@
         }
 
         StructuredGraph getMethodSubstitutionGraph(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, ReplacementsImpl replacements, IntrinsicContext.CompilationContext context,
-                        StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
+                        StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
             Integer startOffset = snippetStartOffsets.get(plugin.toString() + context);
             if (startOffset == null) {
                 throw GraalError.shouldNotReachHere("plugin graph not found: " + plugin + " with " + context);
             }
 
             ResolvedJavaType accessingClass = replacements.getProviders().getMetaAccess().lookupJavaType(plugin.getDeclaringClass());
-            return decodeGraph(original, accessingClass, startOffset, replacements, context, allowAssumptions, options);
+            return decodeGraph(original, accessingClass, startOffset, replacements, context, allowAssumptions, cancellable, options);
         }
 
         @SuppressWarnings("try")
-        private StructuredGraph decodeGraph(ResolvedJavaMethod method, ResolvedJavaType accessingClass, int startOffset, ReplacementsImpl replacements,
-                        IntrinsicContext.CompilationContext context, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
+        private StructuredGraph decodeGraph(ResolvedJavaMethod method,
+                        ResolvedJavaType accessingClass,
+                        int startOffset,
+                        ReplacementsImpl replacements,
+                        IntrinsicContext.CompilationContext context,
+                        StructuredGraph.AllowAssumptions allowAssumptions,
+                        Cancellable cancellable,
+                        OptionValues options) {
             Providers providers = replacements.getProviders();
             EncodedGraph encodedGraph = new SymbolicEncodedGraph(snippetEncoding, startOffset, snippetObjects, snippetNodeClasses,
                             methodKey(method), accessingClass, method.getDeclaringClass());
             try (DebugContext debug = replacements.openDebugContext("SVMSnippet_", method, options)) {
-                StructuredGraph result = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).setIsSubstitution(true).build();
+                StructuredGraph result = new StructuredGraph.Builder(options, debug, allowAssumptions).cancellable(cancellable).method(method).setIsSubstitution(true).build();
                 PEGraphDecoder graphDecoder = new SubstitutionGraphDecoder(providers, result, replacements, null, method, context, encodedGraph);
 
                 graphDecoder.decode(method, result.isSubstitution(), encodedGraph.trackNodeSourcePosition());
@@ -432,7 +438,7 @@
                             originalProvider.getConstantReflection());
             HotSpotProviders newProviders = new HotSpotProviders(originalProvider.getMetaAccess(), originalProvider.getCodeCache(), constantReflection,
                             originalProvider.getConstantFieldProvider(), originalProvider.getForeignCalls(), originalProvider.getLowerer(), null, originalProvider.getSuites(),
-                            originalProvider.getRegisters(), snippetReflection, originalProvider.getWordTypes(), originalProvider.getGraphBuilderPlugins());
+                            originalProvider.getRegisters(), snippetReflection, originalProvider.getWordTypes(), originalProvider.getGraphBuilderPlugins(), originalProvider.getGC());
             HotSpotSnippetReplacementsImpl filteringReplacements = new HotSpotSnippetReplacementsImpl(newProviders, snippetReflection,
                             originalProvider.getReplacements().getDefaultReplacementBytecodeProvider(), originalProvider.getCodeCache().getTarget());
             filteringReplacements.setGraphBuilderPlugins(originalProvider.getReplacements().getGraphBuilderPlugins());
@@ -1048,7 +1054,7 @@
         }
 
         @Override
-        protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
+        protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) {
             if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
                 return false;
             }
@@ -1056,7 +1062,7 @@
                 // Always defer Fold until decode time but NodeIntrinsics may fold if they are able.
                 return false;
             }
-            return super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType);
+            return super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType);
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,6 +38,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.graalvm.compiler.core.GraalServiceThread;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.debug.CSVUtil;
 import org.graalvm.compiler.debug.GraalError;
@@ -445,7 +446,7 @@
             enabled = true;
         }
         if (Options.TimedDynamicCounters.getValue(options) > 0) {
-            Thread thread = new Thread() {
+            Thread thread = new GraalServiceThread(new Runnable() {
                 long lastTime = System.nanoTime();
 
                 @Override
@@ -462,7 +463,7 @@
                         }
                     }
                 }
-            };
+            });
             thread.setDaemon(true);
             thread.setPriority(Thread.MAX_PRIORITY);
             thread.start();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ArrayRangePostWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.gc.shared.ArrayRangeWriteBarrier;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
-public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
-    public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
-
-    public G1ArrayRangePostWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
-        super(TYPE, address, length, elementStride);
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ArrayRangePreWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.gc.shared.ArrayRangeWriteBarrier;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
-public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
-    public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
-
-    public G1ArrayRangePreWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
-        super(TYPE, address, length, elementStride);
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019, 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.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.gc.shared.BarrierSet;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
-import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
-import org.graalvm.compiler.nodes.memory.FixedAccessNode;
-import org.graalvm.compiler.nodes.memory.HeapAccess;
-import org.graalvm.compiler.nodes.memory.ReadNode;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-import org.graalvm.compiler.nodes.type.StampTool;
-
-public class G1BarrierSet extends BarrierSet {
-
-    public G1BarrierSet(GraalHotSpotVMConfig vmConfig) {
-        super(vmConfig);
-    }
-
-    @Override
-    public void addReadNodeBarriers(ReadNode node, StructuredGraph graph) {
-        if (node.getBarrierType() == HeapAccess.BarrierType.WEAK_FIELD) {
-            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
-            graph.addAfterFixed(node, barrier);
-        }
-    }
-
-    @Override
-    public void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean init = node.getLocationIdentity().isInit();
-                if (!init || !getVMConfig().useDeferredInitBarriers) {
-                    if (!init) {
-                        // The pre barrier does nothing if the value being read is null, so it can
-                        // be explicitly skipped when this is an initializing store.
-                        addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
-                    }
-                    boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                    addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
-                }
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
-                addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph);
-                addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) {
-        if (!write.isInitialization()) {
-            // The pre barrier does nothing if the value being read is null, so it can
-            // be explicitly skipped when this is an initializing store.
-            G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
-            graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier);
-        }
-        G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
-        graph.addAfterFixed(write.asNode(), g1ArrayRangePostWriteBarrier);
-    }
-
-    private static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
-        G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck));
-        preBarrier.setStateBefore(node.stateBefore());
-        node.setNullCheck(false);
-        node.setStateBefore(null);
-        graph.addBeforeFixed(node, preBarrier);
-    }
-
-    private static void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
-        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
-        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull)));
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1PostWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
-public class G1PostWriteBarrier extends ObjectWriteBarrier {
-
-    public static final NodeClass<G1PostWriteBarrier> TYPE = NodeClass.create(G1PostWriteBarrier.class);
-    protected final boolean alwaysNull;
-
-    public G1PostWriteBarrier(AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
-        this(TYPE, address, value, precise, alwaysNull);
-    }
-
-    private G1PostWriteBarrier(NodeClass<? extends G1PostWriteBarrier> c, AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
-        super(c, address, value, precise);
-        this.alwaysNull = alwaysNull;
-    }
-
-    public boolean alwaysNull() {
-        return alwaysNull;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1PreWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.DeoptimizingNode;
-import org.graalvm.compiler.nodes.FrameState;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
-public final class G1PreWriteBarrier extends ObjectWriteBarrier implements DeoptimizingNode.DeoptBefore {
-
-    public static final NodeClass<G1PreWriteBarrier> TYPE = NodeClass.create(G1PreWriteBarrier.class);
-
-    @OptionalInput(InputType.State) private FrameState stateBefore;
-    private final boolean nullCheck;
-    private final boolean doLoad;
-
-    public G1PreWriteBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad, boolean nullCheck) {
-        super(TYPE, address, expectedObject, true);
-        this.doLoad = doLoad;
-        this.nullCheck = nullCheck;
-    }
-
-    public ValueNode getExpectedObject() {
-        return getValue();
-    }
-
-    public boolean doLoad() {
-        return doLoad;
-    }
-
-    public boolean getNullCheck() {
-        return nullCheck;
-    }
-
-    @Override
-    public boolean canDeoptimize() {
-        return nullCheck;
-    }
-
-    @Override
-    public FrameState stateBefore() {
-        return stateBefore;
-    }
-
-    @Override
-    public void setStateBefore(FrameState state) {
-        updateUsages(stateBefore, state);
-        stateBefore = state;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1ReferentFieldReadBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.g1;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-/**
- * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent
- * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an
- * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
- * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
- */
-@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
-public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier {
-    public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
-
-    private final boolean doLoad;
-
-    public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad) {
-        super(TYPE, address, expectedObject, true);
-        this.doLoad = doLoad;
-    }
-
-    public ValueNode getExpectedObject() {
-        return getValue();
-    }
-
-    public boolean doLoad() {
-        return doLoad;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/ArrayRangeWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.nodes.WriteBarrier;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-import org.graalvm.compiler.nodes.spi.Lowerable;
-
-@NodeInfo
-public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable {
-
-    public static final NodeClass<ArrayRangeWriteBarrier> TYPE = NodeClass.create(ArrayRangeWriteBarrier.class);
-    @Input(InputType.Association) AddressNode address;
-    @Input ValueNode length;
-
-    private final int elementStride;
-
-    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, AddressNode address, ValueNode length, int elementStride) {
-        super(c);
-        this.address = address;
-        this.length = length;
-        this.elementStride = elementStride;
-    }
-
-    public AddressNode getAddress() {
-        return address;
-    }
-
-    public ValueNode getLength() {
-        return length;
-    }
-
-    public int getElementStride() {
-        return elementStride;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019, 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.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
-import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
-import org.graalvm.compiler.nodes.memory.ReadNode;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-
-public abstract class BarrierSet {
-    private final GraalHotSpotVMConfig vmConfig;
-
-    protected BarrierSet(GraalHotSpotVMConfig vmConfig) {
-        this.vmConfig = vmConfig;
-    }
-
-    public final GraalHotSpotVMConfig getVMConfig() {
-        return vmConfig;
-    }
-
-    public abstract void addReadNodeBarriers(ReadNode node, StructuredGraph graph);
-
-    public abstract void addWriteNodeBarriers(WriteNode node, StructuredGraph graph);
-
-    public abstract void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph);
-
-    public abstract void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph);
-
-    public abstract void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph);
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2019, 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.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
-import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
-import org.graalvm.compiler.nodes.memory.FixedAccessNode;
-import org.graalvm.compiler.nodes.memory.HeapAccess;
-import org.graalvm.compiler.nodes.memory.ReadNode;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-import org.graalvm.compiler.nodes.type.StampTool;
-
-public class CardTableBarrierSet extends BarrierSet {
-
-    public CardTableBarrierSet(GraalHotSpotVMConfig vmConfig) {
-        super(vmConfig);
-    }
-
-    @Override
-    public void addReadNodeBarriers(ReadNode node, StructuredGraph graph) {
-        // Nothing to do here.
-    }
-
-    @Override
-    public void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                boolean init = node.getLocationIdentity().isInit();
-                if (!init || !getVMConfig().useDeferredInitBarriers) {
-                    addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
-                }
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph) {
-        HeapAccess.BarrierType barrierType = node.getBarrierType();
-        switch (barrierType) {
-            case NONE:
-                // nothing to do
-                break;
-            case FIELD:
-            case ARRAY:
-            case UNKNOWN:
-                boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
-                addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
-                break;
-            default:
-                throw new GraalError("unexpected barrier type: " + barrierType);
-        }
-    }
-
-    @Override
-    public void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) {
-        SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
-        graph.addAfterFixed(write.asNode(), serialArrayRangeWriteBarrier);
-    }
-
-    protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
-        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
-        if (alwaysNull) {
-            // Serial barrier isn't needed for null value
-            return;
-        }
-        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise)));
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/ObjectWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.nodes.WriteBarrier;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo
-public abstract class ObjectWriteBarrier extends WriteBarrier {
-
-    public static final NodeClass<ObjectWriteBarrier> TYPE = NodeClass.create(ObjectWriteBarrier.class);
-    @Input(InputType.Association) protected AddressNode address;
-    @OptionalInput protected ValueNode value;
-    protected final boolean precise;
-
-    protected ObjectWriteBarrier(NodeClass<? extends ObjectWriteBarrier> c, AddressNode address, ValueNode value, boolean precise) {
-        super(c);
-        this.address = address;
-        this.value = value;
-        this.precise = precise;
-    }
-
-    public ValueNode getValue() {
-        return value;
-    }
-
-    public AddressNode getAddress() {
-        return address;
-    }
-
-    public boolean usePrecise() {
-        return precise;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/SerialArrayRangeWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
-public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
-    public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
-
-    public SerialArrayRangeWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
-        super(TYPE, address, length, elementStride);
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/SerialWriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.gc.shared;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-
-@NodeInfo(cycles = CYCLES_8, size = SIZE_4)
-public class SerialWriteBarrier extends ObjectWriteBarrier {
-
-    public static final NodeClass<SerialWriteBarrier> TYPE = NodeClass.create(SerialWriteBarrier.class);
-
-    public SerialWriteBarrier(AddressNode address, boolean precise) {
-        this(TYPE, address, precise);
-    }
-
-    protected SerialWriteBarrier(NodeClass<? extends SerialWriteBarrier> c, AddressNode address, boolean precise) {
-        super(c, address, null, precise);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,8 +32,8 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.Phase;
-import org.graalvm.compiler.phases.common.ExpandLogicPhase;
-import org.graalvm.compiler.phases.common.FixReadsPhase;
+import org.graalvm.compiler.phases.common.UseTrappingNullChecksPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
 import org.graalvm.compiler.phases.tiers.Suites;
 import org.graalvm.compiler.phases.tiers.SuitesCreator;
@@ -55,10 +55,11 @@
     public Suites createSuites(OptionValues options) {
         Suites suites = super.createSuites(options);
 
-        ListIterator<BasePhase<? super LowTierContext>> findPhase = suites.getLowTier().findPhase(FixReadsPhase.class);
+        ListIterator<BasePhase<? super LowTierContext>> findPhase = suites.getLowTier().findPhase(UseTrappingNullChecksPhase.class);
         if (findPhase == null) {
-            findPhase = suites.getLowTier().findPhase(ExpandLogicPhase.class);
+            findPhase = suites.getLowTier().findPhase(SchedulePhase.class);
         }
+        findPhase.previous();
         findPhase.add(addressLowering);
 
         return suites;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,7 +26,6 @@
 
 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs;
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
 import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
@@ -60,13 +59,6 @@
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ReferentFieldReadBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialArrayRangeWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode;
 import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
@@ -82,6 +74,8 @@
 import org.graalvm.compiler.hotspot.replacements.AssertionSnippets;
 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
 import org.graalvm.compiler.hotspot.replacements.HashCodeSnippets;
+import org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets;
+import org.graalvm.compiler.hotspot.replacements.HotSpotSerialWriteBarrierSnippets;
 import org.graalvm.compiler.hotspot.replacements.HubGetClassNode;
 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
 import org.graalvm.compiler.hotspot.replacements.InstanceOfSnippets;
@@ -92,7 +86,6 @@
 import org.graalvm.compiler.hotspot.replacements.ObjectCloneSnippets;
 import org.graalvm.compiler.hotspot.replacements.StringToBytesSnippets;
 import org.graalvm.compiler.hotspot.replacements.UnsafeLoadSnippets;
-import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
 import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
 import org.graalvm.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets;
 import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
@@ -135,6 +128,13 @@
 import org.graalvm.compiler.nodes.extended.OSRStartNode;
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.extended.StoreHubNode;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.gc.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
 import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
@@ -191,7 +191,8 @@
     protected InstanceOfSnippets.Templates instanceofSnippets;
     protected NewObjectSnippets.Templates newObjectSnippets;
     protected MonitorSnippets.Templates monitorSnippets;
-    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
+    protected HotSpotSerialWriteBarrierSnippets.Templates serialWriteBarrierSnippets;
+    protected HotSpotG1WriteBarrierSnippets.Templates g1WriteBarrierSnippets;
     protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
     protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
     protected AssertionSnippets.Templates assertionSnippets;
@@ -220,7 +221,8 @@
         instanceofSnippets = new InstanceOfSnippets.Templates(options, factories, runtime, providers, target);
         newObjectSnippets = new NewObjectSnippets.Templates(options, factories, runtime, providers, target, config);
         monitorSnippets = new MonitorSnippets.Templates(options, factories, runtime, providers, target, config.useFastLocking);
-        writeBarrierSnippets = new WriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config);
+        g1WriteBarrierSnippets = new HotSpotG1WriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config);
+        serialWriteBarrierSnippets = new HotSpotSerialWriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config);
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(options, factories, providers, target);
         unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(options, factories, providers, target);
         assertionSnippets = new AssertionSnippets.Templates(options, factories, providers, target);
@@ -228,11 +230,14 @@
         stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target);
         hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target);
         resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
-        if (!JavaVersionUtil.Java8OrEarlier && GeneratePIC.getValue(options)) {
+        objectCloneSnippets = new ObjectCloneSnippets.Templates(options, factories, providers, target);
+        foreignCallSnippets = new ForeignCallSnippets.Templates(options, factories, providers, target);
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
+            // AOT only introduced in JDK 9
+            profileSnippets = null;
+        } else {
             profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
         }
-        objectCloneSnippets = new ObjectCloneSnippets.Templates(options, factories, providers, target);
-        foreignCallSnippets = new ForeignCallSnippets.Templates(options, factories, providers, target);
     }
 
     public ArrayCopySnippets.Templates getArraycopySnippets() {
@@ -340,19 +345,19 @@
             } else if (n instanceof ArrayCopyWithDelayedLoweringNode) {
                 arraycopySnippets.lower((ArrayCopyWithDelayedLoweringNode) n, tool);
             } else if (n instanceof G1PreWriteBarrier) {
-                writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+                g1WriteBarrierSnippets.lower((G1PreWriteBarrier) n, tool);
             } else if (n instanceof G1PostWriteBarrier) {
-                writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+                g1WriteBarrierSnippets.lower((G1PostWriteBarrier) n, tool);
             } else if (n instanceof G1ReferentFieldReadBarrier) {
-                writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+                g1WriteBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, tool);
             } else if (n instanceof SerialWriteBarrier) {
-                writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+                serialWriteBarrierSnippets.lower((SerialWriteBarrier) n, tool);
             } else if (n instanceof SerialArrayRangeWriteBarrier) {
-                writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+                serialWriteBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
             } else if (n instanceof G1ArrayRangePreWriteBarrier) {
-                writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+                g1WriteBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, tool);
             } else if (n instanceof G1ArrayRangePostWriteBarrier) {
-                writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+                g1WriteBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, tool);
             } else if (n instanceof NewMultiArrayNode) {
                 if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
                     newObjectSnippets.lower((NewMultiArrayNode) n, tool);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGCProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.meta;
+
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.gc.BarrierSet;
+import org.graalvm.compiler.nodes.gc.CardTableBarrierSet;
+import org.graalvm.compiler.nodes.gc.G1BarrierSet;
+import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.spi.GCProvider;
+
+public class HotSpotGCProvider implements GCProvider {
+    private final BarrierSet barrierSet;
+
+    public HotSpotGCProvider(GraalHotSpotVMConfig config) {
+        this.barrierSet = createBarrierSet(config);
+    }
+
+    @Override
+    public BarrierSet getBarrierSet() {
+        return barrierSet;
+    }
+
+    private BarrierSet createBarrierSet(GraalHotSpotVMConfig config) {
+        boolean useDeferredInitBarriers = config.useDeferredInitBarriers;
+        if (config.useG1GC) {
+            return new G1BarrierSet() {
+                @Override
+                protected boolean writeRequiresPostBarrier(FixedAccessNode initializingWrite, ValueNode writtenValue) {
+                    if (!super.writeRequiresPostBarrier(initializingWrite, writtenValue)) {
+                        return false;
+                    }
+                    return !useDeferredInitBarriers || !isWriteToNewObject(initializingWrite);
+                }
+            };
+        } else {
+            return new CardTableBarrierSet() {
+                @Override
+                protected boolean writeRequiresBarrier(FixedAccessNode initializingWrite, ValueNode writtenValue) {
+                    if (!super.writeRequiresBarrier(initializingWrite, writtenValue)) {
+                        return false;
+                    }
+                    return !useDeferredInitBarriers || !isWriteToNewObject(initializingWrite);
+                }
+            };
+        }
+    }
+
+    /**
+     * For initializing writes, the last allocation executed by the JVM is guaranteed to be
+     * automatically card marked so it's safe to skip the card mark in the emitted code.
+     */
+    protected boolean isWriteToNewObject(FixedAccessNode initializingWrite) {
+        if (!initializingWrite.getLocationIdentity().isInit()) {
+            return false;
+        }
+        // This is only allowed for the last allocation in sequence
+        ValueNode base = initializingWrite.getAddress().getBase();
+        if (base instanceof AbstractNewObjectNode) {
+            Node pred = initializingWrite.predecessor();
+            while (pred != null) {
+                if (pred == base) {
+                    return true;
+                }
+                if (pred instanceof AbstractNewObjectNode) {
+                    initializingWrite.getDebug().log(DebugContext.INFO_LEVEL, "Disallowed deferred init because %s was last allocation instead of %s", pred, base);
+                    return false;
+                }
+                pred = pred.predecessor();
+            }
+        }
+        initializingWrite.getDebug().log(DebugContext.INFO_LEVEL, "Unable to find allocation for deferred init for %s with base %s", initializingWrite, base);
+        return false;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,7 +30,6 @@
 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MutableCallSite;
@@ -101,6 +100,7 @@
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode;
 import org.graalvm.compiler.serviceprovider.GraalServices;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.WordOperationPlugin;
 import org.graalvm.compiler.word.WordTypes;
 import jdk.internal.vm.compiler.word.LocationIdentity;
@@ -278,7 +278,7 @@
 
     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
         Registration r;
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
         } else {
             r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
@@ -403,7 +403,7 @@
     }
 
     private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "toBytes", char[].class, int.class, int.class);
             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
@@ -437,7 +437,7 @@
     public static final String constantPoolClass;
 
     static {
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             cbcEncryptName = "encrypt";
             cbcDecryptName = "decrypt";
             aesEncryptName = "encryptBlock";
@@ -476,7 +476,7 @@
         Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
         if (config.useMultiplyToLenIntrinsic()) {
             assert config.multiplyToLen != 0L;
-            if (Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
                 r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
                                 int[].class);
             } else {
@@ -503,7 +503,7 @@
         boolean useSha256 = config.useSHA256Intrinsics();
         boolean useSha512 = config.useSHA512Intrinsics();
 
-        if (!Java8OrEarlier && (useSha1 || useSha256 || useSha512)) {
+        if (JavaVersionUtil.JAVA_SPEC > 8 && (useSha1 || useSha256 || useSha512)) {
             Registration r = new Registration(plugins, "sun.security.provider.DigestBase", bytecodeProvider);
             r.registerMethodSubstitution(DigestBaseSubstitutions.class, "implCompressMultiBlock0", Receiver.class, byte[].class, int.class, int.class);
         }
@@ -602,7 +602,7 @@
         if (config.useCRC32Intrinsics) {
             Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
             r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
-            if (Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC <= 8) {
                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
             } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -81,24 +81,24 @@
 import static org.graalvm.compiler.hotspot.HotSpotHostBackend.THROW_DELAYED_STACKOVERFLOW_ERROR;
 import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
 import static org.graalvm.compiler.hotspot.replacements.AssertionSnippets.ASSERTION_VM_MESSAGE_C;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets.G1WBPOSTCALL;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets.G1WBPRECALL;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotG1WriteBarrierSnippets.VALIDATE_OBJECT;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.Log.LOG_OBJECT;
+import static org.graalvm.compiler.hotspot.replacements.Log.LOG_PRIMITIVE;
+import static org.graalvm.compiler.hotspot.replacements.Log.LOG_PRINTF;
 import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITORENTER;
 import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITOREXIT;
 import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE;
 import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE_OR_NULL;
 import static org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions.THREAD_IS_INTERRUPTED;
-import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPOSTCALL;
-import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPRECALL;
-import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.VALIDATE_OBJECT;
 import static org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub.EXCEPTION_HANDLER_FOR_PC;
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.VM_MESSAGE_C;
 import static org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub.EXCEPTION_HANDLER_FOR_RETURN_ADDRESS;
 import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
-import static org.graalvm.compiler.replacements.Log.LOG_OBJECT;
-import static org.graalvm.compiler.replacements.Log.LOG_PRIMITIVE;
-import static org.graalvm.compiler.replacements.Log.LOG_PRINTF;
 import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotProviders.java	Fri Jun 28 14:36:42 2019 +0530
@@ -50,17 +50,18 @@
     private final SnippetReflectionProvider snippetReflection;
     private final HotSpotWordTypes wordTypes;
     private final Plugins graphBuilderPlugins;
+    private final HotSpotGCProvider gc;
 
     public HotSpotProviders(MetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantField,
-                    HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, SuitesProvider suites,
-                    HotSpotRegistersProvider registers,
-                    SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins) {
-        super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider());
+                    HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, SuitesProvider suites, HotSpotRegistersProvider registers,
+                    SnippetReflectionProvider snippetReflection, HotSpotWordTypes wordTypes, Plugins graphBuilderPlugins, HotSpotGCProvider gc) {
+        super(metaAccess, codeCache, constantReflection, constantField, foreignCalls, lowerer, replacements, new HotSpotStampProvider(), gc);
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
         this.wordTypes = wordTypes;
         this.graphBuilderPlugins = graphBuilderPlugins;
+        this.gc = gc;
     }
 
     @Override
@@ -94,51 +95,54 @@
     }
 
     @Override
+    public HotSpotGCProvider getGC() {
+        return gc;
+    }
+
+    @Override
     public Providers copyWith(MetaAccessProvider substitution) {
         return new HotSpotProviders(substitution, getCodeCache(), getConstantReflection(), getConstantFieldProvider(), getForeignCalls(), getLowerer(), getReplacements(), getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(CodeCacheProvider substitution) {
         return new HotSpotProviders(getMetaAccess(), (HotSpotCodeCacheProvider) substitution, getConstantReflection(), getConstantFieldProvider(), getForeignCalls(), getLowerer(), getReplacements(),
-                        getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getSuites(), getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(ConstantReflectionProvider substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), substitution, getConstantFieldProvider(), getForeignCalls(), getLowerer(), getReplacements(), getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(ConstantFieldProvider substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), getConstantReflection(), substitution, getForeignCalls(), getLowerer(), getReplacements(), getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(ForeignCallsProvider substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), getConstantReflection(), getConstantFieldProvider(), (HotSpotForeignCallsProvider) substitution, getLowerer(), getReplacements(),
-                        getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getSuites(), getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(LoweringProvider substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), getConstantReflection(), getConstantFieldProvider(), getForeignCalls(), substitution, getReplacements(), getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     @Override
     public Providers copyWith(Replacements substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), getConstantReflection(), getConstantFieldProvider(), getForeignCalls(), getLowerer(), substitution, getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins());
+                        getRegisters(), getSnippetReflection(), getWordTypes(), getGraphBuilderPlugins(), getGC());
     }
 
     public Providers copyWith(Plugins substitution) {
         return new HotSpotProviders(getMetaAccess(), getCodeCache(), getConstantReflection(), getConstantFieldProvider(), getForeignCalls(), getLowerer(), getReplacements(), getSuites(),
-                        getRegisters(), getSnippetReflection(), getWordTypes(), substitution);
+                        getRegisters(), getSnippetReflection(), getWordTypes(), substitution, getGC());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -39,8 +39,6 @@
 import org.graalvm.compiler.hotspot.lir.VerifyMaxRegisterSizePhase;
 import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
 import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
 import org.graalvm.compiler.hotspot.phases.aot.AOTInliningPolicy;
 import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase;
 import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase;
@@ -112,11 +110,6 @@
             }
         }
 
-        ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase(config));
-        if (VerifyPhases.getValue(options)) {
-            ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config));
-        }
-
         return ret;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,19 +24,18 @@
 
 package org.graalvm.compiler.hotspot.meta;
 
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
-
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.WordFactory;
 
 @ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
 public class HotSpotUnsafeSubstitutions {
 
-    public static final String copyMemoryName = Java8OrEarlier ? "copyMemory" : "copyMemory0";
+    public static final String copyMemoryName = JavaVersionUtil.JAVA_SPEC <= 8 ? "copyMemory" : "copyMemory0";
 
     @SuppressWarnings("unused")
     @MethodSubstitution(isStatic = false)
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/AllocaNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,8 +27,6 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import java.util.BitSet;
-
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.lir.VirtualStackSlot;
@@ -39,7 +37,6 @@
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordTypes;
 
-import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 
 /**
@@ -55,26 +52,14 @@
      */
     protected final int slots;
 
-    /**
-     * The indexes of the object pointer slots in the block. Each such object pointer slot must be
-     * initialized before any safepoint in the method otherwise the garbage collector will see
-     * garbage values when processing these slots.
-     */
-    protected final BitSet objects;
-
     public AllocaNode(@InjectedNodeParameter WordTypes wordTypes, int slots) {
-        this(slots, wordTypes.getWordKind(), new BitSet());
-    }
-
-    public AllocaNode(int slots, JavaKind wordKind, BitSet objects) {
-        super(TYPE, StampFactory.forKind(wordKind));
+        super(TYPE, StampFactory.forKind(wordTypes.getWordKind()));
         this.slots = slots;
-        this.objects = objects;
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        VirtualStackSlot array = gen.getLIRGeneratorTool().allocateStackSlots(slots, objects, null);
+        VirtualStackSlot array = gen.getLIRGeneratorTool().allocateStackSlots(slots);
         Value result = gen.getLIRGeneratorTool().emitAddress(array);
         gen.setResult(this, result);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/DimensionsNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,8 +28,6 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import java.util.BitSet;
-
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.lir.VirtualStackSlot;
@@ -64,7 +62,7 @@
         int size = rank * 4;
         int wordSize = lirGen.target().wordSize;
         int slots = roundUp(size, wordSize) / wordSize;
-        VirtualStackSlot array = lirGen.allocateStackSlots(slots, new BitSet(0), null);
+        VirtualStackSlot array = lirGen.allocateStackSlots(slots);
         Value result = lirGen.emitAddress(array);
         gen.setResult(this, result);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/MonitorCounterNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,8 +26,6 @@
 
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import java.util.BitSet;
-
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -56,7 +54,7 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         assert graph().getNodes().filter(MonitorCounterNode.class).count() == 1 : "monitor counters not canonicalized to single instance";
-        VirtualStackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(1, new BitSet(0), null);
+        VirtualStackSlot counter = gen.getLIRGeneratorTool().getResult().getFrameMapBuilder().allocateStackSlots(1);
         Value result = gen.getLIRGeneratorTool().emitAddress(counter);
         gen.setResult(this, result);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/VMErrorNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.compiler.replacements.Log;
 import org.graalvm.compiler.replacements.nodes.CStringConstant;
 
 import jdk.vm.ci.code.CodeUtil;
@@ -46,8 +45,8 @@
 import jdk.vm.ci.meta.Value;
 
 /**
- * Causes the VM to exit with a description of the current Java location and an optional
- * {@linkplain Log#printf(String, long) formatted} error message specified.
+ * Causes the VM to exit with a description of the current Java location and an optional printf
+ * formatted error message specified.
  */
 @NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
 public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/WriteBarrier.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.nodes;
-
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.spi.Lowerable;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-
-@NodeInfo
-public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
-
-    public static final NodeClass<WriteBarrier> TYPE = NodeClass.create(WriteBarrier.class);
-
-    protected WriteBarrier(NodeClass<? extends WriteBarrier> c) {
-        super(c, StampFactory.forVoid());
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        assert graph().getGuardsStage().areFrameStatesAtDeopts();
-        tool.getLowerer().lower(this, tool);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,6 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
-import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.Constant;
@@ -84,7 +83,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         assert constant != null : "Expected the value to fold: " + value;
         Value result;
-        if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
+        if (constant instanceof HotSpotObjectConstant) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant);
         } else if (constant instanceof HotSpotMetaspaceConstant) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Fri Jun 28 14:36:42 2019 +0530
@@ -45,7 +45,6 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.word.Word;
 
-import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.Constant;
@@ -101,7 +100,7 @@
         Value result;
         LIRFrameState fs = gen.state(this);
         assert fs != null : "The stateAfter is null";
-        if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
+        if (constant instanceof HotSpotObjectConstant) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs);
         } else if (constant instanceof HotSpotMetaspaceConstant) {
             if (action == HotSpotConstantLoadAction.RESOLVE) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,9 +28,9 @@
 
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.phases.VerifyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.JavaKind;
@@ -41,10 +41,10 @@
  *
  * @see LoadJavaMirrorWithKlassPhase
  */
-public class AheadOfTimeVerificationPhase extends VerifyPhase<PhaseContext> {
+public class AheadOfTimeVerificationPhase extends VerifyPhase<CoreProviders> {
 
     @Override
-    protected void verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, CoreProviders context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             if (isIllegalObjectConstant(node)) {
                 throw new VerificationError("illegal object constant: " + node);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,9 +44,9 @@
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
@@ -68,7 +68,7 @@
  *
  * @see AheadOfTimeVerificationPhase
  */
-public class LoadJavaMirrorWithKlassPhase extends BasePhase<PhaseContext> {
+public class LoadJavaMirrorWithKlassPhase extends BasePhase<CoreProviders> {
 
     private final CompressEncoding oopEncoding;
 
@@ -76,7 +76,7 @@
         this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null;
     }
 
-    private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, JavaConstant constant) {
+    private ValueNode getClassConstantReplacement(StructuredGraph graph, CoreProviders context, JavaConstant constant) {
         if (constant instanceof HotSpotObjectConstant) {
             ConstantReflectionProvider constantReflection = context.getConstantReflection();
             ResolvedJavaType type = constantReflection.asJavaType(constant);
@@ -131,7 +131,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             JavaConstant constant = node.asJavaConstant();
             ValueNode freadNode = getClassConstantReplacement(graph, context, constant);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -282,7 +282,7 @@
         NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.TYPE);
         EntryMarkerNode osr = osrNodes.first();
         if (osr == null) {
-            throw new PermanentBailoutException("No OnStackReplacementNode generated");
+            throw new GraalError("No OnStackReplacementNode generated");
         }
         if (osrNodes.count() > 1) {
             throw new GraalError("Multiple OnStackReplacementNodes generated");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.phases;
-
-import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.gc.g1.G1BarrierSet;
-import org.graalvm.compiler.hotspot.gc.shared.BarrierSet;
-import org.graalvm.compiler.hotspot.gc.shared.CardTableBarrierSet;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
-import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
-import org.graalvm.compiler.nodes.memory.ReadNode;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-import org.graalvm.compiler.phases.Phase;
-
-public class WriteBarrierAdditionPhase extends Phase {
-
-    private BarrierSet barrierSet;
-
-    public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) {
-        this.barrierSet = createBarrierSet(config);
-    }
-
-    @SuppressWarnings("try")
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (Node n : graph.getNodes()) {
-            try (DebugCloseable scope = n.graph().withNodeSourcePosition(n)) {
-                if (n instanceof ReadNode) {
-                    barrierSet.addReadNodeBarriers((ReadNode) n, graph);
-                } else if (n instanceof WriteNode) {
-                    barrierSet.addWriteNodeBarriers((WriteNode) n, graph);
-                } else if (n instanceof LoweredAtomicReadAndWriteNode) {
-                    LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n;
-                    barrierSet.addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
-                } else if (n instanceof AbstractCompareAndSwapNode) {
-                    barrierSet.addCASBarriers((AbstractCompareAndSwapNode) n, graph);
-                } else if (n instanceof ArrayRangeWrite) {
-                    ArrayRangeWrite node = (ArrayRangeWrite) n;
-                    if (node.writesObjectArray()) {
-                        barrierSet.addArrayRangeBarriers(node, graph);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean checkContract() {
-        return false;
-    }
-
-    private BarrierSet createBarrierSet(GraalHotSpotVMConfig config) {
-        if (config.useG1GC) {
-            return createG1BarrierSet(config);
-        } else {
-            return createCardTableBarrierSet(config);
-        }
-    }
-
-    protected BarrierSet createCardTableBarrierSet(GraalHotSpotVMConfig config) {
-        return new CardTableBarrierSet(config);
-    }
-
-    protected BarrierSet createG1BarrierSet(GraalHotSpotVMConfig config) {
-        return new G1BarrierSet(config);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-package org.graalvm.compiler.hotspot.phases;
-
-import java.util.Iterator;
-
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeFlood;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.ArrayRangeWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
-import org.graalvm.compiler.nodeinfo.Verbosity;
-import org.graalvm.compiler.nodes.DeoptimizingNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.LoopBeginNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
-import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
-import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
-import org.graalvm.compiler.nodes.memory.FixedAccessNode;
-import org.graalvm.compiler.nodes.memory.HeapAccess;
-import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
-import org.graalvm.compiler.nodes.memory.ReadNode;
-import org.graalvm.compiler.nodes.memory.WriteNode;
-import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
-import org.graalvm.compiler.nodes.type.StampTool;
-import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.compiler.phases.Phase;
-
-/**
- * Verification phase that checks if, for every write, at least one write barrier is present at all
- * paths leading to the previous safepoint. For every write, necessitating a write barrier, a
- * bottom-up traversal of the graph is performed up to the previous safepoints via all possible
- * paths. If, for a certain path, no write barrier satisfying the processed write is found, an
- * assertion is generated.
- */
-public class WriteBarrierVerificationPhase extends Phase {
-
-    private final GraalHotSpotVMConfig config;
-
-    public WriteBarrierVerificationPhase(GraalHotSpotVMConfig config) {
-        this.config = config;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        processWrites(graph);
-    }
-
-    private void processWrites(StructuredGraph graph) {
-        for (Node node : graph.getNodes()) {
-            if (isObjectWrite(node) || isObjectArrayRangeWrite(node)) {
-                if (node instanceof WriteNode) {
-                    WriteNode writeNode = (WriteNode) node;
-                    if (StampTool.isPointerAlwaysNull(writeNode.value())) {
-                        continue;
-                    }
-                }
-                validateWrite(node);
-            }
-        }
-    }
-
-    private void validateWrite(Node write) {
-        /*
-         * The currently validated write is checked in order to discover if it has an appropriate
-         * attached write barrier.
-         */
-        if (hasAttachedBarrier((FixedWithNextNode) write)) {
-            return;
-        }
-        NodeFlood frontier = write.graph().createNodeFlood();
-        expandFrontier(frontier, write);
-        Iterator<Node> iterator = frontier.iterator();
-        while (iterator.hasNext()) {
-            Node currentNode = iterator.next();
-            if (isSafepoint(currentNode)) {
-                throw new AssertionError("Write barrier must be present " + write.toString(Verbosity.All) + " / " + write.inputs());
-            }
-            if (useG1GC()) {
-                if (!(currentNode instanceof G1PostWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
-                    expandFrontier(frontier, currentNode);
-                }
-            } else {
-                if (!(currentNode instanceof SerialWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode)) ||
-                                ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
-                    expandFrontier(frontier, currentNode);
-                }
-            }
-        }
-    }
-
-    private boolean useG1GC() {
-        return config.useG1GC;
-    }
-
-    private boolean hasAttachedBarrier(FixedWithNextNode node) {
-        final Node next = node.next();
-        final Node previous = node.predecessor();
-        boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization());
-        if (node instanceof WriteNode) {
-            WriteNode writeNode = (WriteNode) node;
-            if (config.useDeferredInitBarriers && writeNode.getLocationIdentity().isInit()) {
-                return true;
-            }
-            if (writeNode.getLocationIdentity().isInit()) {
-                validatePreBarrier = false;
-            }
-        }
-        if (isObjectWrite(node)) {
-            return (isObjectBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isObjectBarrier(node, previous));
-        } else if (isObjectArrayRangeWrite(node)) {
-            return (isArrayBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isArrayBarrier(node, previous));
-        } else {
-            return true;
-        }
-    }
-
-    private static boolean isObjectBarrier(FixedWithNextNode node, final Node next) {
-        return next instanceof ObjectWriteBarrier && validateBarrier((FixedAccessNode) node, (ObjectWriteBarrier) next);
-    }
-
-    private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) {
-        return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWrite) node).getAddress() == ((ArrayRangeWriteBarrier) next).getAddress();
-    }
-
-    private static boolean isObjectWrite(Node node) {
-        // Read nodes with barrier attached (G1 Ref field) are not validated yet.
-        return node instanceof FixedAccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode);
-    }
-
-    private static boolean isObjectArrayRangeWrite(Node node) {
-        return node instanceof ArrayRangeWrite && ((ArrayRangeWrite) node).writesObjectArray();
-    }
-
-    private static void expandFrontier(NodeFlood frontier, Node node) {
-        for (Node previousNode : node.cfgPredecessors()) {
-            if (previousNode != null) {
-                frontier.add(previousNode);
-            }
-        }
-    }
-
-    private static boolean isSafepoint(Node node) {
-        if (node instanceof FixedAccessNode) {
-            // Implicit null checks on reads or writes do not count.
-            return false;
-        }
-        /*
-         * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed
-         * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write
-         * barriers inside loops, derived from writes outside loops, can not be permitted.
-         */
-        return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
-    }
-
-    private static ValueNode getValueWritten(FixedWithNextNode write) {
-        if (write instanceof WriteNode) {
-            return ((WriteNode) write).value();
-        } else if (write instanceof LogicCompareAndSwapNode) {
-            return ((LogicCompareAndSwapNode) write).getNewValue();
-        } else if (write instanceof LoweredAtomicReadAndWriteNode) {
-            return ((LoweredAtomicReadAndWriteNode) write).getNewValue();
-        } else {
-            throw GraalError.shouldNotReachHere(String.format("unexpected write node %s", write));
-        }
-    }
-
-    private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) {
-        assert write instanceof WriteNode || write instanceof LogicCompareAndSwapNode || write instanceof ValueCompareAndSwapNode ||
-                        write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write;
-        if (!barrier.usePrecise()) {
-            if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) {
-                return GraphUtil.unproxify(((OffsetAddressNode) barrier.getAddress()).getBase()) == GraphUtil.unproxify(((OffsetAddressNode) write.getAddress()).getBase());
-            }
-        }
-        return barrier.getAddress() == write.getAddress();
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,10 +30,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
 import jdk.internal.vm.compiler.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
@@ -43,12 +39,16 @@
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.graph.MergeableState;
 import org.graalvm.compiler.phases.graph.PostOrderNodeIterator;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public class EliminateRedundantInitializationPhase extends BasePhase<PhaseContext> {
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class EliminateRedundantInitializationPhase extends BasePhase<CoreProviders> {
     /**
      * Find each {@link Invoke} that has a corresponding {@link InitializeKlassNode}. These
      * {@link InitializeKlassNode} are redundant and are removed.
@@ -252,7 +252,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         removeInitsAtStaticCalls(graph);
         removeRedundantInits(graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -61,12 +61,12 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
@@ -78,7 +78,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
+public class ReplaceConstantNodesPhase extends BasePhase<CoreProviders> {
 
     private final boolean verifyFingerprints;
 
@@ -448,7 +448,7 @@
      * @param node
      * @param context
      */
-    private static void handleLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, LoadMethodCountersNode node, PhaseContext context) {
+    private static void handleLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, LoadMethodCountersNode node, CoreProviders context) {
         ResolvedJavaType type = node.getMethod().getDeclaringClass();
         Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
         ConstantReflectionProvider constantReflection = context.getConstantReflection();
@@ -466,7 +466,7 @@
      * @param stateMapper
      * @param context
      */
-    private static void replaceLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, PhaseContext context) {
+    private static void replaceLoadMethodCounters(StructuredGraph graph, FrameStateMapperClosure stateMapper, CoreProviders context) {
         new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true).apply(graph, false);
 
         for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
@@ -496,7 +496,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         FrameStateMapperClosure stateMapper = new FrameStateMapperClosure(graph);
         ReentrantNodeIterator.apply(stateMapper, graph.start(), null);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/profiling/FinalizeProfileNodesPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -46,16 +46,16 @@
 import org.graalvm.compiler.nodes.calc.MulNode;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-public class FinalizeProfileNodesPhase extends BasePhase<PhaseContext> {
+public class FinalizeProfileNodesPhase extends BasePhase<CoreProviders> {
     private int inlineeInvokeNotificationFreqLog;
 
     public static class Options {
@@ -156,7 +156,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         if (simpleMethodHeuristic(graph)) {
             removeAllProfilingNodes(graph);
             return;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotG1WriteBarrierSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.replacements.SnippetCounter.Group;
+import org.graalvm.compiler.replacements.SnippetCounter.Group.Factory;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.gc.G1WriteBarrierSnippets;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.WordFactory;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+
+public final class HotSpotG1WriteBarrierSnippets extends G1WriteBarrierSnippets {
+    public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
+    public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class);
+    public static final ForeignCallDescriptor VALIDATE_OBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class);
+
+    private final GraalHotSpotVMConfig config;
+    private final Register threadRegister;
+
+    public HotSpotG1WriteBarrierSnippets(GraalHotSpotVMConfig config, HotSpotRegistersProvider registers) {
+        this.config = config;
+        this.threadRegister = registers.getThreadRegister();
+    }
+
+    @Override
+    protected Word getThread() {
+        return HotSpotReplacementsUtil.registerAsWord(threadRegister);
+    }
+
+    @Override
+    protected int wordSize() {
+        return HotSpotReplacementsUtil.wordSize();
+    }
+
+    @Override
+    protected int objectArrayIndexScale() {
+        return ReplacementsUtil.arrayIndexScale(INJECTED_METAACCESS, JavaKind.Object);
+    }
+
+    @Override
+    protected int satbQueueMarkingOffset() {
+        return HotSpotReplacementsUtil.g1SATBQueueMarkingOffset(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected int satbQueueBufferOffset() {
+        return HotSpotReplacementsUtil.g1SATBQueueBufferOffset(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected int satbQueueIndexOffset() {
+        return HotSpotReplacementsUtil.g1SATBQueueIndexOffset(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected int cardQueueBufferOffset() {
+        return HotSpotReplacementsUtil.g1CardQueueBufferOffset(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected int cardQueueIndexOffset() {
+        return HotSpotReplacementsUtil.g1CardQueueIndexOffset(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected byte dirtyCardValue() {
+        return HotSpotReplacementsUtil.dirtyCardValue(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected byte youngCardValue() {
+        return HotSpotReplacementsUtil.g1YoungCardValue(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected Word cardTableAddress() {
+        return WordFactory.unsigned(GraalHotSpotVMConfigNode.cardTableAddress());
+    }
+
+    @Override
+    protected int cardTableShift() {
+        return HotSpotReplacementsUtil.cardTableShift(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected int logOfHeapRegionGrainBytes() {
+        return GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes();
+    }
+
+    @Override
+    protected ForeignCallDescriptor preWriteBarrierCallDescriptor() {
+        return G1WBPRECALL;
+    }
+
+    @Override
+    protected ForeignCallDescriptor postWriteBarrierCallDescriptor() {
+        return G1WBPOSTCALL;
+    }
+
+    @Override
+    protected boolean verifyOops() {
+        return HotSpotReplacementsUtil.verifyOops(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected boolean verifyBarrier() {
+        return ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED || config.verifyBeforeGC || config.verifyAfterGC;
+    }
+
+    @Override
+    protected long gcTotalCollectionsAddress() {
+        return HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    protected ForeignCallDescriptor verifyOopCallDescriptor() {
+        return HotSpotForeignCallsProviderImpl.VERIFY_OOP;
+    }
+
+    @Override
+    protected ForeignCallDescriptor validateObjectCallDescriptor() {
+        return VALIDATE_OBJECT;
+    }
+
+    @Override
+    protected ForeignCallDescriptor printfCallDescriptor() {
+        return Log.LOG_PRINTF;
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo g1PreWriteBarrier;
+        private final SnippetInfo g1ReferentReadBarrier;
+        private final SnippetInfo g1PostWriteBarrier;
+        private final SnippetInfo g1ArrayRangePreWriteBarrier;
+        private final SnippetInfo g1ArrayRangePostWriteBarrier;
+
+        private final G1WriteBarrierLowerer lowerer;
+
+        public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, Group.Factory factory, HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config) {
+            super(options, factories, providers, providers.getSnippetReflection(), target);
+            this.lowerer = new HotspotG1WriteBarrierLowerer(config, factory);
+
+            HotSpotG1WriteBarrierSnippets receiver = new HotSpotG1WriteBarrierSnippets(config, providers.getRegisters());
+            g1PreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION, SATB_QUEUE_INDEX_LOCATION,
+                            SATB_QUEUE_BUFFER_LOCATION);
+            g1ReferentReadBarrier = g1PreWriteBarrier;
+            g1PostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1PostWriteBarrier", null, receiver, GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION, CARD_QUEUE_INDEX_LOCATION,
+                            CARD_QUEUE_BUFFER_LOCATION);
+            g1ArrayRangePreWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", null, receiver, GC_INDEX_LOCATION, GC_LOG_LOCATION, SATB_QUEUE_MARKING_LOCATION,
+                            SATB_QUEUE_INDEX_LOCATION, SATB_QUEUE_BUFFER_LOCATION);
+            g1ArrayRangePostWriteBarrier = snippet(G1WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", null, receiver, GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION,
+                            CARD_QUEUE_INDEX_LOCATION, CARD_QUEUE_BUFFER_LOCATION);
+        }
+
+        public void lower(G1PreWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, g1PreWriteBarrier, barrier, tool);
+        }
+
+        public void lower(G1ReferentFieldReadBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, g1ReferentReadBarrier, barrier, tool);
+        }
+
+        public void lower(G1PostWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, g1PostWriteBarrier, barrier, tool);
+        }
+
+        public void lower(G1ArrayRangePreWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, g1ArrayRangePreWriteBarrier, barrier, tool);
+        }
+
+        public void lower(G1ArrayRangePostWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, g1ArrayRangePostWriteBarrier, barrier, tool);
+        }
+    }
+
+    static final class HotspotG1WriteBarrierLowerer extends G1WriteBarrierLowerer {
+        private final CompressEncoding oopEncoding;
+
+        HotspotG1WriteBarrierLowerer(GraalHotSpotVMConfig config, Factory factory) {
+            super(factory);
+            oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null;
+        }
+
+        @Override
+        public ValueNode uncompress(ValueNode expected) {
+            assert oopEncoding != null;
+            return HotSpotCompressionNode.uncompress(expected, oopEncoding);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotSerialWriteBarrierSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
+
+import org.graalvm.compiler.debug.DebugHandlersFactory;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.nodes.gc.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.replacements.SnippetCounter.Group;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.gc.SerialWriteBarrierSnippets;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.WordFactory;
+
+import jdk.vm.ci.code.TargetDescription;
+
+public class HotSpotSerialWriteBarrierSnippets extends SerialWriteBarrierSnippets {
+    private final GraalHotSpotVMConfig config;
+
+    public HotSpotSerialWriteBarrierSnippets(GraalHotSpotVMConfig config) {
+        this.config = config;
+    }
+
+    @Override
+    public Word cardTableAddress() {
+        return WordFactory.unsigned(GraalHotSpotVMConfigNode.cardTableAddress());
+    }
+
+    @Override
+    public int cardTableShift() {
+        return HotSpotReplacementsUtil.cardTableShift(INJECTED_VMCONFIG);
+    }
+
+    @Override
+    public boolean verifyBarrier() {
+        return ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED || config.verifyBeforeGC || config.verifyAfterGC;
+    }
+
+    @Override
+    protected byte dirtyCardValue() {
+        return config.dirtyCardValue;
+    }
+
+    public static class Templates extends AbstractTemplates {
+        private final SnippetInfo serialImpreciseWriteBarrier;
+        private final SnippetInfo serialPreciseWriteBarrier;
+        private final SnippetInfo serialArrayRangeWriteBarrier;
+
+        private final SerialWriteBarrierLowerer lowerer;
+
+        public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, Group.Factory factory, HotSpotProviders providers, TargetDescription target, GraalHotSpotVMConfig config) {
+            super(options, factories, providers, providers.getSnippetReflection(), target);
+            this.lowerer = new SerialWriteBarrierLowerer(factory);
+
+            HotSpotSerialWriteBarrierSnippets receiver = new HotSpotSerialWriteBarrierSnippets(config);
+            serialImpreciseWriteBarrier = snippet(SerialWriteBarrierSnippets.class, "serialImpreciseWriteBarrier", null, receiver, GC_CARD_LOCATION);
+            serialPreciseWriteBarrier = snippet(SerialWriteBarrierSnippets.class, "serialPreciseWriteBarrier", null, receiver, GC_CARD_LOCATION);
+            serialArrayRangeWriteBarrier = snippet(SerialWriteBarrierSnippets.class, "serialArrayRangeWriteBarrier", null, receiver, GC_CARD_LOCATION);
+        }
+
+        public void lower(SerialWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, serialPreciseWriteBarrier, serialImpreciseWriteBarrier, barrier, tool);
+        }
+
+        public void lower(SerialArrayRangeWriteBarrier barrier, LoweringTool tool) {
+            lowerer.lower(this, serialArrayRangeWriteBarrier, barrier, tool);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/Log.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
+
+import java.io.PrintStream;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.meta.JavaKind;
+
+//JaCoCo Exclude
+
+/**
+ * Provides {@link PrintStream}-like logging facility.
+ */
+public final class Log {
+
+    public static final ForeignCallDescriptor LOG_PRIMITIVE = new ForeignCallDescriptor("logPrimitive", void.class, int.class, long.class, boolean.class);
+    public static final ForeignCallDescriptor LOG_OBJECT = new ForeignCallDescriptor("logObject", void.class, Object.class, boolean.class, boolean.class);
+    public static final ForeignCallDescriptor LOG_PRINTF = new ForeignCallDescriptor("logPrintf", void.class, Word.class, long.class, long.class, long.class);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logObject, Object object, boolean asString, boolean newline);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logPrimitive, int typeChar, long value, boolean newline);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, Word format, long v1, long v2, long v3);
+
+    public static void print(boolean value) {
+        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, false);
+    }
+
+    public static void print(byte value) {
+        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, false);
+    }
+
+    public static void print(char value) {
+        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, false);
+    }
+
+    public static void print(short value) {
+        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, false);
+    }
+
+    public static void print(int value) {
+        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, false);
+    }
+
+    public static void print(long value) {
+        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, false);
+    }
+
+    /**
+     * Prints a formatted string to the log stream.
+     *
+     * @param format a C style printf format value that can contain at most one conversion specifier
+     *            (i.e., a sequence of characters starting with '%').
+     * @param value the value associated with the conversion specifier
+     */
+    public static void printf(String format, long value) {
+        printf(LOG_PRINTF, cstring(format), value, 0L, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2) {
+        printf(LOG_PRINTF, cstring(format), v1, v2, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2, long v3) {
+        printf(LOG_PRINTF, cstring(format), v1, v2, v3);
+    }
+
+    public static void print(float value) {
+        if (Float.isNaN(value)) {
+            print("NaN");
+        } else if (value == Float.POSITIVE_INFINITY) {
+            print("Infinity");
+        } else if (value == Float.NEGATIVE_INFINITY) {
+            print("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), false);
+        }
+    }
+
+    public static void print(double value) {
+        if (Double.isNaN(value)) {
+            print("NaN");
+        } else if (value == Double.POSITIVE_INFINITY) {
+            print("Infinity");
+        } else if (value == Double.NEGATIVE_INFINITY) {
+            print("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false);
+        }
+    }
+
+    public static void print(String value) {
+        log(LOG_OBJECT, value, true, false);
+    }
+
+    public static void printObject(Object o) {
+        log(LOG_OBJECT, o, false, false);
+    }
+
+    public static void println(boolean value) {
+        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, true);
+    }
+
+    public static void println(byte value) {
+        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, true);
+    }
+
+    public static void println(char value) {
+        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, true);
+    }
+
+    public static void println(short value) {
+        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, true);
+    }
+
+    public static void println(int value) {
+        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, true);
+    }
+
+    public static void println(long value) {
+        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, true);
+    }
+
+    public static void println(float value) {
+        if (Float.isNaN(value)) {
+            println("NaN");
+        } else if (value == Float.POSITIVE_INFINITY) {
+            println("Infinity");
+        } else if (value == Float.NEGATIVE_INFINITY) {
+            println("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), true);
+        }
+    }
+
+    public static void println(double value) {
+        if (Double.isNaN(value)) {
+            println("NaN");
+        } else if (value == Double.POSITIVE_INFINITY) {
+            println("Infinity");
+        } else if (value == Double.NEGATIVE_INFINITY) {
+            println("-Infinity");
+        } else {
+            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true);
+        }
+    }
+
+    public static void println(String value) {
+        log(LOG_OBJECT, value, true, true);
+    }
+
+    public static void printlnObject(Object o) {
+        log(LOG_OBJECT, o, false, true);
+    }
+
+    public static void println() {
+        println("");
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -122,7 +122,6 @@
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
-import org.graalvm.compiler.replacements.Log;
 import org.graalvm.compiler.replacements.SnippetCounter;
 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
@@ -753,7 +752,8 @@
     public static class Templates extends AbstractTemplates {
 
         private final SnippetInfo monitorenter = snippet(MonitorSnippets.class, "monitorenter");
-        private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit");
+        private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit", DISPLACED_MARK_WORD_LOCATION, OBJECT_MONITOR_OWNER_LOCATION, OBJECT_MONITOR_CXQ_LOCATION,
+                        OBJECT_MONITOR_ENTRY_LIST_LOCATION, OBJECT_MONITOR_RECURSION_LOCATION, OBJECT_MONITOR_SUCC_LOCATION);
         private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub");
         private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub");
         private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,6 +38,7 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY_OR_NULL;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_STATE_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
@@ -604,7 +605,7 @@
         } else {
             // Use Word instead of int to avoid extension to long in generated code
             Word off = WordFactory.signed(offset);
-            if (useBulkZeroing && probability(SLOW_PATH_PROBABILITY, size >= getMinimalBulkZeroingSize(INJECTED_OPTIONVALUES))) {
+            if (useBulkZeroing && value == 0 && probability(SLOW_PATH_PROBABILITY, (size - offset) >= getMinimalBulkZeroingSize(INJECTED_OPTIONVALUES))) {
                 if (theCounters != null && theCounters.instanceBulkInit != null) {
                     theCounters.instanceBulkInit.inc();
                 }
@@ -623,7 +624,6 @@
                 for (; off.rawValue() < size; off = off.add(8)) {
                     memory.initializeLong(off, value, LocationIdentity.init());
                 }
-
             }
         }
     }
@@ -714,9 +714,10 @@
 
     public static class Templates extends AbstractTemplates {
 
-        private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
+        private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION,
+                        PROTOTYPE_MARK_WORD_LOCATION);
         private final SnippetInfo allocateInstancePIC = snippet(NewObjectSnippets.class, "allocateInstancePIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
-                        TLAB_END_LOCATION);
+                        TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION);
         private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         private final SnippetInfo allocateArrayPIC = snippet(NewObjectSnippets.class, "allocateArrayPIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         private final SnippetInfo allocatePrimitiveArrayPIC = snippet(NewObjectSnippets.class, "allocatePrimitiveArrayPIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
@@ -724,7 +725,7 @@
         private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
                         TLAB_END_LOCATION);
         private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
-                        TLAB_END_LOCATION);
+                        TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION, CLASS_STATE_LOCATION);
         private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray", TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         private final SnippetInfo newmultiarrayPIC = snippet(NewObjectSnippets.class, "newmultiarrayPIC", TLAB_TOP_LOCATION, TLAB_END_LOCATION);
         private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,9 +24,8 @@
 
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_METAACCESS;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_INTRINSIC_CONTEXT;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
 
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
@@ -37,6 +36,7 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -46,7 +46,7 @@
 @ClassSubstitution(className = "sun.security.provider.SHA2", optional = true)
 public class SHA2Substitutions {
 
-    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
 
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,7 +26,6 @@
 
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_INTRINSIC_CONTEXT;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
@@ -38,6 +37,7 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -47,7 +47,7 @@
 @ClassSubstitution(className = "sun.security.provider.SHA5", optional = true)
 public class SHA5Substitutions {
 
-    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
 
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,7 +26,6 @@
 
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_INTRINSIC_CONTEXT;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
@@ -38,6 +37,7 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -47,7 +47,7 @@
 @ClassSubstitution(className = "sun.security.provider.SHA", optional = true)
 public class SHASubstitutions {
 
-    public static final String implCompressName = Java8OrEarlier ? "implCompress" : "implCompress0";
+    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
 
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,621 +0,0 @@
-/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.hotspot.replacements;
-
-import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueBufferOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueIndexOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueBufferOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueIndexOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueMarkingOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1YoungCardValue;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
-import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
-
-import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
-import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
-import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ArrayRangePreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1PreWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.g1.G1ReferentFieldReadBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialArrayRangeWriteBarrier;
-import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
-import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
-import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
-import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
-import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
-import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
-import org.graalvm.compiler.nodes.NamedLocationIdentity;
-import org.graalvm.compiler.nodes.NodeView;
-import org.graalvm.compiler.nodes.PiNode;
-import org.graalvm.compiler.nodes.SnippetAnchorNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
-import org.graalvm.compiler.nodes.extended.ForeignCallNode;
-import org.graalvm.compiler.nodes.extended.MembarNode;
-import org.graalvm.compiler.nodes.extended.NullCheckNode;
-import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
-import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.nodes.type.NarrowOopStamp;
-import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.replacements.Log;
-import org.graalvm.compiler.replacements.ReplacementsUtil;
-import org.graalvm.compiler.replacements.SnippetCounter;
-import org.graalvm.compiler.replacements.SnippetCounter.Group;
-import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
-import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
-import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
-import org.graalvm.compiler.replacements.Snippets;
-import org.graalvm.compiler.replacements.nodes.AssertionNode;
-import org.graalvm.compiler.replacements.nodes.DirectStoreNode;
-import org.graalvm.compiler.word.Word;
-import jdk.internal.vm.compiler.word.LocationIdentity;
-import jdk.internal.vm.compiler.word.Pointer;
-import jdk.internal.vm.compiler.word.UnsignedWord;
-import jdk.internal.vm.compiler.word.WordFactory;
-
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.JavaKind;
-
-public class WriteBarrierSnippets implements Snippets {
-
-    static class Counters {
-        Counters(SnippetCounter.Group.Factory factory) {
-            Group countersWriteBarriers = factory.createSnippetCounterGroup("WriteBarriers");
-            serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
-            g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of attempted G1 Pre Write Barriers");
-            g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of effective G1 Pre Write Barriers");
-            g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of executed G1 Pre Write Barriers");
-            g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
-            g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
-                            "Number of effective G1 Post Write Barriers (after passing the XOR test)");
-            g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
-                            "Number of effective G1 Post Write Barriers (after passing the NULL test)");
-            g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
-
-        }
-
-        final SnippetCounter serialWriteBarrierCounter;
-        final SnippetCounter g1AttemptedPreWriteBarrierCounter;
-        final SnippetCounter g1EffectivePreWriteBarrierCounter;
-        final SnippetCounter g1ExecutedPreWriteBarrierCounter;
-        final SnippetCounter g1AttemptedPostWriteBarrierCounter;
-        final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter;
-        final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter;
-        final SnippetCounter g1ExecutedPostWriteBarrierCounter;
-    }
-
-    public static final LocationIdentity GC_CARD_LOCATION = NamedLocationIdentity.mutable("GC-Card");
-    public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log");
-    public static final LocationIdentity GC_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Index");
-
-    private static void serialWriteBarrier(Pointer ptr, Counters counters) {
-        counters.serialWriteBarrierCounter.inc();
-        final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
-        Word base = (Word) ptr.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
-        if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
-            base.writeByte((int) startAddress, (byte) 0, GC_CARD_LOCATION);
-        } else {
-            base.writeByte(WordFactory.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION);
-        }
-    }
-
-    @Snippet
-    public static void serialImpreciseWriteBarrier(Object object, @ConstantParameter boolean verifyBarrier, @ConstantParameter Counters counters) {
-        if (verifyBarrier) {
-            verifyNotArray(object);
-        }
-        serialWriteBarrier(Word.objectToTrackedPointer(object), counters);
-    }
-
-    @Snippet
-    public static void serialPreciseWriteBarrier(Address address, @ConstantParameter Counters counters) {
-        serialWriteBarrier(Word.fromAddress(address), counters);
-    }
-
-    @Snippet
-    public static void serialArrayRangeWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
-        if (length == 0) {
-            return;
-        }
-        int cardShift = cardTableShift(INJECTED_VMCONFIG);
-        final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
-        long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
-        long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
-        long count = end - start + 1;
-        while (count-- > 0) {
-            DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean);
-        }
-    }
-
-    @Snippet
-    public static void g1PreWriteBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
-                    @ConstantParameter Register threadRegister, @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
-        if (nullCheck) {
-            NullCheckNode.nullCheck(address);
-        }
-        Word thread = registerAsWord(threadRegister);
-        verifyOop(object);
-        Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
-        Word field = Word.fromAddress(address);
-        Pointer previousOop = Word.objectToTrackedPointer(fixedExpectedObject);
-        byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
-        int gcCycle = 0;
-        if (trace) {
-            Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
-            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
-            log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
-            log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(fixedExpectedObject).rawValue());
-            log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
-            log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
-            log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
-        }
-        counters.g1AttemptedPreWriteBarrierCounter.inc();
-        // If the concurrent marker is enabled, the barrier is issued.
-        if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
-            // If the previous value has to be loaded (before the write), the load is issued.
-            // The load is always issued except the cases of CAS and referent field.
-            if (probability(LIKELY_PROBABILITY, doLoad)) {
-                previousOop = Word.objectToTrackedPointer(field.readObject(0, BarrierType.NONE));
-                if (trace) {
-                    log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
-                    verifyOop(previousOop.toObject());
-                }
-            }
-            counters.g1EffectivePreWriteBarrierCounter.inc();
-            // If the previous value is null the barrier should not be issued.
-            if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
-                counters.g1ExecutedPreWriteBarrierCounter.inc();
-                // If the thread-local SATB buffer is full issue a native call which will
-                // initialize a new one and add the entry.
-                Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
-                Word indexValue = indexAddress.readWord(0);
-                if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
-                    Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
-                    Word nextIndex = indexValue.subtract(wordSize());
-                    Word logAddress = bufferAddress.add(nextIndex);
-                    // Log the object to be marked as well as update the SATB's buffer next index.
-                    logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
-                    indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
-                } else {
-                    g1PreBarrierStub(G1WBPRECALL, previousOop.toObject());
-                }
-            }
-        }
-    }
-
-    @Snippet
-    public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter boolean verifyBarrier,
-                    @ConstantParameter Register threadRegister, @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
-        Word thread = registerAsWord(threadRegister);
-        Object fixedValue = FixedValueAnchorNode.getObject(value);
-        verifyOop(object);
-        verifyOop(fixedValue);
-        validateObject(object, fixedValue);
-        Pointer oop;
-        if (usePrecise) {
-            oop = Word.fromAddress(address);
-        } else {
-            if (verifyBarrier) {
-                verifyNotArray(object);
-            }
-            oop = Word.objectToTrackedPointer(object);
-        }
-        int gcCycle = 0;
-        if (trace) {
-            Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
-            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
-            log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
-            log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
-        }
-        Pointer writtenValue = Word.objectToTrackedPointer(fixedValue);
-        // The result of the xor reveals whether the installed pointer crosses heap regions.
-        // In case it does the write barrier has to be issued.
-        final int logOfHeapRegionGrainBytes = GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes();
-        UnsignedWord xorResult = (oop.xor(writtenValue)).unsignedShiftRight(logOfHeapRegionGrainBytes);
-
-        // Calculate the address of the card to be enqueued to the
-        // thread local card queue.
-        UnsignedWord cardBase = oop.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
-        final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
-        int displacement = 0;
-        if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
-            displacement = (int) startAddress;
-        } else {
-            cardBase = cardBase.add(WordFactory.unsigned(startAddress));
-        }
-        Word cardAddress = (Word) cardBase.add(displacement);
-
-        counters.g1AttemptedPostWriteBarrierCounter.inc();
-        if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
-            counters.g1EffectiveAfterXORPostWriteBarrierCounter.inc();
-
-            // If the written value is not null continue with the barrier addition.
-            if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
-                byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
-                counters.g1EffectiveAfterNullPostWriteBarrierCounter.inc();
-
-                // If the card is already dirty, (hence already enqueued) skip the insertion.
-                if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
-                    MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
-                    byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
-                    if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
-                        log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), WordFactory.unsigned((int) cardByte).rawValue());
-                        cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
-                        counters.g1ExecutedPostWriteBarrierCounter.inc();
-
-                        // If the thread local card queue is full, issue a native call which will
-                        // initialize a new one and add the card entry.
-                        Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
-                        Word indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
-                        if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
-                            Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
-                            Word nextIndex = indexValue.subtract(wordSize());
-                            Word logAddress = bufferAddress.add(nextIndex);
-                            // Log the object to be scanned as well as update
-                            // the card queue's next index.
-                            logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
-                            indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
-                        } else {
-                            g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private static void verifyNotArray(Object object) {
-        if (object != null) {
-            // Manually build the null check and cast because we're in snippet that's lowered late.
-            AssertionNode.assertion(false, !PiNode.piCastNonNull(object, SnippetAnchorNode.anchor()).getClass().isArray(), "imprecise card mark used with array");
-        }
-    }
-
-    @Snippet
-    public static void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
-        Word thread = registerAsWord(threadRegister);
-        byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
-        // If the concurrent marker is not enabled or the vector length is zero, return.
-        if (markingValue == (byte) 0 || length == 0) {
-            return;
-        }
-        Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
-        Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
-        long indexValue = indexAddress.readWord(0).rawValue();
-        final int scale = ReplacementsUtil.arrayIndexScale(INJECTED_METAACCESS, JavaKind.Object);
-        long start = getPointerToFirstArrayElement(address, length, elementStride);
-
-        for (int i = 0; i < length; i++) {
-            Word arrElemPtr = WordFactory.pointer(start + i * scale);
-            Pointer oop = Word.objectToTrackedPointer(arrElemPtr.readObject(0, BarrierType.NONE));
-            verifyOop(oop.toObject());
-            if (oop.notEqual(0)) {
-                if (indexValue != 0) {
-                    indexValue = indexValue - wordSize();
-                    Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
-                    // Log the object to be marked as well as update the SATB's buffer next index.
-                    logAddress.writeWord(0, oop, GC_LOG_LOCATION);
-                    indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
-                } else {
-                    g1PreBarrierStub(G1WBPRECALL, oop.toObject());
-                }
-            }
-        }
-    }
-
-    @Snippet
-    public static void g1ArrayRangePostWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
-        if (length == 0) {
-            return;
-        }
-        Word thread = registerAsWord(threadRegister);
-        Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
-        Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
-        long indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG)).rawValue();
-
-        int cardShift = cardTableShift(INJECTED_VMCONFIG);
-        final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
-        long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
-        long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
-        long count = end - start + 1;
-
-        while (count-- > 0) {
-            Word cardAddress = WordFactory.unsigned((start + cardStart) + count);
-            byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
-            // If the card is already dirty, (hence already enqueued) skip the insertion.
-            if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
-                MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
-                byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
-                if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
-                    cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
-                    // If the thread local card queue is full, issue a native call which will
-                    // initialize a new one and add the card entry.
-                    if (indexValue != 0) {
-                        indexValue = indexValue - wordSize();
-                        Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
-                        // Log the object to be scanned as well as update
-                        // the card queue's next index.
-                        logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
-                        indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
-                    } else {
-                        g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
-                    }
-                }
-            }
-        }
-    }
-
-    private static long getPointerToFirstArrayElement(Address address, int length, int elementStride) {
-        long result = Word.fromAddress(address).rawValue();
-        if (elementStride < 0) {
-            // the address points to the place after the last array element
-            result = result + elementStride * length;
-        }
-        return result;
-    }
-
-    private static long getPointerToLastArrayElement(Address address, int length, int elementStride) {
-        long result = Word.fromAddress(address).rawValue();
-        if (elementStride < 0) {
-            // the address points to the place after the last array element
-            result = result + elementStride;
-        } else {
-            result = result + (length - 1) * elementStride;
-        }
-        return result;
-    }
-
-    public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    private static native void g1PreBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
-
-    public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    public static native void g1PostBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word card);
-
-    public static class Templates extends AbstractTemplates {
-
-        private final SnippetInfo serialImpreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialImpreciseWriteBarrier", GC_CARD_LOCATION);
-        private final SnippetInfo serialPreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialPreciseWriteBarrier", GC_CARD_LOCATION);
-        private final SnippetInfo serialArrayRangeWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayRangeWriteBarrier");
-        private final SnippetInfo g1PreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
-        private final SnippetInfo g1ReferentReadBarrier = g1PreWriteBarrier;
-        private final SnippetInfo g1PostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
-        private final SnippetInfo g1ArrayRangePreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
-        private final SnippetInfo g1ArrayRangePostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
-
-        private final CompressEncoding oopEncoding;
-        private final Counters counters;
-        private final boolean verifyBarrier;
-        private final long gcTotalCollectionsAddress;
-
-        public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, Group.Factory factory, HotSpotProviders providers, TargetDescription target,
-                        GraalHotSpotVMConfig config) {
-            super(options, factories, providers, providers.getSnippetReflection(), target);
-            this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null;
-            this.verifyBarrier = ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED || config.verifyBeforeGC || config.verifyAfterGC;
-            this.gcTotalCollectionsAddress = config.gcTotalCollectionsAddress();
-            this.counters = new Counters(factory);
-        }
-
-        public boolean traceBarrier(StructuredGraph graph) {
-            long startCycle = GraalOptions.GCDebugStartCycle.getValue(graph.getOptions());
-            return startCycle > 0 && ((Pointer) WordFactory.pointer(gcTotalCollectionsAddress)).readLong(0) > startCycle;
-        }
-
-        public void lower(SerialWriteBarrier writeBarrier, LoweringTool tool) {
-            Arguments args;
-            if (writeBarrier.usePrecise()) {
-                args = new Arguments(serialPreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-                args.add("address", writeBarrier.getAddress());
-            } else {
-                args = new Arguments(serialImpreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-                OffsetAddressNode address = (OffsetAddressNode) writeBarrier.getAddress();
-                args.add("object", address.getBase());
-                args.addConst("verifyBarrier", verifyBarrier);
-            }
-            args.addConst("counters", counters);
-            template(writeBarrier, args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
-            Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("address", arrayRangeWriteBarrier.getAddress());
-            args.add("length", arrayRangeWriteBarrier.getLength());
-            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
-            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) {
-            Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage(), tool.getLoweringStage());
-            AddressNode address = writeBarrierPre.getAddress();
-            args.add("address", address);
-            if (address instanceof OffsetAddressNode) {
-                args.add("object", ((OffsetAddressNode) address).getBase());
-            } else {
-                args.add("object", null);
-            }
-
-            ValueNode expected = writeBarrierPre.getExpectedObject();
-            if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
-                assert oopEncoding != null;
-                expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
-            }
-            args.add("expectedObject", expected);
-
-            args.addConst("doLoad", writeBarrierPre.doLoad());
-            args.addConst("nullCheck", writeBarrierPre.getNullCheck());
-            args.addConst("threadRegister", registers.getThreadRegister());
-            args.addConst("trace", traceBarrier(writeBarrierPre.graph()));
-            args.addConst("counters", counters);
-            template(writeBarrierPre, args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
-            Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            AddressNode address = readBarrier.getAddress();
-            args.add("address", address);
-            if (address instanceof OffsetAddressNode) {
-                args.add("object", ((OffsetAddressNode) address).getBase());
-            } else {
-                args.add("object", null);
-            }
-
-            ValueNode expected = readBarrier.getExpectedObject();
-            if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
-                assert oopEncoding != null;
-                expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
-            }
-
-            args.add("expectedObject", expected);
-            args.addConst("doLoad", readBarrier.doLoad());
-            args.addConst("nullCheck", false);
-            args.addConst("threadRegister", registers.getThreadRegister());
-            args.addConst("trace", traceBarrier(readBarrier.graph()));
-            args.addConst("counters", counters);
-            template(readBarrier, args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) {
-            StructuredGraph graph = writeBarrierPost.graph();
-            if (writeBarrierPost.alwaysNull()) {
-                graph.removeFixed(writeBarrierPost);
-                return;
-            }
-            Arguments args = new Arguments(g1PostWriteBarrier, graph.getGuardsStage(), tool.getLoweringStage());
-            AddressNode address = writeBarrierPost.getAddress();
-            args.add("address", address);
-            if (address instanceof OffsetAddressNode) {
-                args.add("object", ((OffsetAddressNode) address).getBase());
-            } else {
-                assert writeBarrierPost.usePrecise() : "found imprecise barrier that's not an object access " + writeBarrierPost;
-                args.add("object", null);
-            }
-
-            ValueNode value = writeBarrierPost.getValue();
-            if (value.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
-                assert oopEncoding != null;
-                value = HotSpotCompressionNode.uncompress(value, oopEncoding);
-            }
-            args.add("value", value);
-
-            args.addConst("usePrecise", writeBarrierPost.usePrecise());
-            args.addConst("verifyBarrier", verifyBarrier);
-            args.addConst("threadRegister", registers.getThreadRegister());
-            args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
-            args.addConst("counters", counters);
-            template(writeBarrierPost, args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
-            Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("address", arrayRangeWriteBarrier.getAddress());
-            args.add("length", arrayRangeWriteBarrier.getLength());
-            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
-            args.addConst("threadRegister", registers.getThreadRegister());
-            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
-        }
-
-        public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
-            Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("address", arrayRangeWriteBarrier.getAddress());
-            args.add("length", arrayRangeWriteBarrier.getLength());
-            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
-            args.addConst("threadRegister", registers.getThreadRegister());
-            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
-        }
-    }
-
-    /**
-     * Log method of debugging purposes.
-     */
-    public static void log(boolean enabled, String format, long value) {
-        if (enabled) {
-            Log.printf(format, value);
-        }
-    }
-
-    public static void log(boolean enabled, String format, long value1, long value2) {
-        if (enabled) {
-            Log.printf(format, value1, value2);
-        }
-    }
-
-    public static void log(boolean enabled, String format, long value1, long value2, long value3) {
-        if (enabled) {
-            Log.printf(format, value1, value2, value3);
-        }
-    }
-
-    /**
-     * Validation helper method which performs sanity checks on write operations. The addresses of
-     * both the object and the value being written are checked in order to determine if they reside
-     * in a valid heap region. If an object is stale, an invalid access is performed in order to
-     * prematurely crash the VM and debug the stack trace of the faulty method.
-     */
-    public static void validateObject(Object parent, Object child) {
-        if (verifyOops(INJECTED_VMCONFIG) && child != null) {
-            Word parentWord = Word.objectToTrackedPointer(parent);
-            Word childWord = Word.objectToTrackedPointer(child);
-            if (!validateOop(VALIDATE_OBJECT, parentWord, childWord)) {
-                log(true, "Verification ERROR, Parent: %p Child: %p\n", parentWord.rawValue(), childWord.rawValue());
-                VMErrorNode.vmError("Verification ERROR, Parent: %p\n", parentWord.rawValue());
-            }
-        }
-    }
-
-    public static final ForeignCallDescriptor VALIDATE_OBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word parent, Word object);
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java	Fri Jun 28 14:36:42 2019 +0530
@@ -48,7 +48,7 @@
     }
 
     // JDK-8201593: Print array length in ArrayIndexOutOfBoundsException.
-    private static final boolean PRINT_LENGTH_IN_EXCEPTION = JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 11;
+    private static final boolean PRINT_LENGTH_IN_EXCEPTION = JavaVersionUtil.JAVA_SPEC >= 11;
     private static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length();
     private static final String STR_INDEX = "Index ";
     private static final String STR_OUTOFBOUNDSFORLENGTH = " out of bounds for length ";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Fri Jun 28 14:36:42 2019 +0530
@@ -42,7 +42,6 @@
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.replacements.SnippetTemplate;
 import org.graalvm.compiler.replacements.Snippets;
 
@@ -104,9 +103,8 @@
             new RemoveValueProxyPhase().apply(graph);
             graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
             CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-            PhaseContext context = new PhaseContext(providers);
-            canonicalizer.apply(graph, context);
-            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            canonicalizer.apply(graph, providers);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, providers);
         } catch (Throwable e) {
             throw debug.handle(e);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java	Fri Jun 28 14:36:42 2019 +0530
@@ -39,7 +39,7 @@
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
 import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
-import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.hotspot.replacements.Log;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.WordFactory;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,7 +35,6 @@
 import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch;
 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
-import static jdk.vm.ci.meta.DeoptimizationReason.TypeCheckedInliningViolated;
 import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode;
 import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
@@ -256,8 +255,6 @@
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
-import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_FAST_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_SLOW_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING;
@@ -288,6 +285,7 @@
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.RetryableBailoutException;
 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
@@ -355,6 +353,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
 import org.graalvm.compiler.nodes.calc.AddNode;
 import org.graalvm.compiler.nodes.calc.AndNode;
 import org.graalvm.compiler.nodes.calc.CompareNode;
@@ -390,7 +389,6 @@
 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
 import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
-import org.graalvm.compiler.nodes.extended.LoadMethodNode;
 import org.graalvm.compiler.nodes.extended.MembarNode;
 import org.graalvm.compiler.nodes.extended.StateSplitProxyNode;
 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
@@ -449,7 +447,6 @@
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.JavaTypeProfile;
-import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
 import jdk.vm.ci.meta.LineNumberTable;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ProfilingInfo;
@@ -627,7 +624,8 @@
     }
 
     static class IntrinsicScope extends InliningScope {
-        boolean sawInvalidFrameState;
+        StateSplit returnStateSplit;
+        ArrayList<StateSplit> invalidStateUsers;
 
         IntrinsicScope(BytecodeParser parser) {
             super(parser);
@@ -650,30 +648,64 @@
                 isRootCompilation = false;
             }
             processPlaceholderFrameStates(isRootCompilation);
-            if (sawInvalidFrameState) {
+            if (invalidStateUsers != null) {
                 JavaKind returnKind = parser.getInvokeReturnType().getJavaKind();
-                FrameStateBuilder frameStateBuilder = parser.frameState;
-                ValueNode returnValue = frameStateBuilder.pop(returnKind);
-                StructuredGraph graph = parser.lastInstr.graph();
-                StateSplitProxyNode proxy = graph.add(new StateSplitProxyNode(returnValue));
-                parser.lastInstr.setNext(proxy);
-                frameStateBuilder.push(returnKind, proxy);
-                proxy.setStateAfter(parser.createFrameState(parser.stream.nextBCI(), proxy));
-                parser.lastInstr = proxy;
+                ValueNode returnValue = parser.frameState.pop(returnKind);
+                if (invalidStateUsers.size() == 1 && invalidStateUsers.get(0) == parser.lastInstr) {
+                    updateSplitFrameState(invalidStateUsers.get(0), returnKind, returnValue);
+                } else if (parser.lastInstr instanceof MergeNode) {
+                    ValuePhiNode returnValues = null;
+                    MergeNode merge = (MergeNode) parser.lastInstr;
+
+                    if (returnValue instanceof ValuePhiNode && ((ValuePhiNode) returnValue).merge() == parser.lastInstr) {
+                        returnValues = (ValuePhiNode) returnValue;
+                    }
+                    if (invalidStateUsers.remove(merge)) {
+                        updateSplitFrameState(merge, returnKind, returnValue);
+                    }
+                    for (EndNode pred : merge.cfgPredecessors()) {
+                        Node lastPred = pred.predecessor();
+                        if (invalidStateUsers.remove(lastPred)) {
+                            ValueNode predReturnValue = returnValue;
+                            if (returnValues != null) {
+                                int index = merge.phiPredecessorIndex(pred);
+                                predReturnValue = ((ValuePhiNode) returnValue).valueAt(index);
+                            }
+                            updateSplitFrameState((StateSplit) lastPred, returnKind, predReturnValue);
+                        }
+                    }
+                    if (invalidStateUsers.size() != 0) {
+                        throw new GraalError("unexpected StateSplit above merge %s", invalidStateUsers);
+                    }
+                } else {
+                    throw new GraalError("unexpected node between return StateSplit and last instruction %s", parser.lastInstr);
+                }
+                // Restore the original return value
+                parser.frameState.push(returnKind, returnValue);
+            }
+        }
+
+        private void updateSplitFrameState(StateSplit split, JavaKind returnKind, ValueNode returnValue) {
+            parser.frameState.push(returnKind, returnValue);
+            FrameState oldState = split.stateAfter();
+            split.setStateAfter(parser.createFrameState(parser.stream.nextBCI(), split));
+            parser.frameState.pop(returnKind);
+            if (oldState.hasNoUsages()) {
+                oldState.safeDelete();
             }
         }
 
         @Override
         protected void handleReturnMismatch(StructuredGraph g, FrameState fs) {
-            // If the intrinsic returns a non-void value, then any frame
-            // state with an empty stack is invalid as it cannot
-            // be used to deoptimize to just after the call returns.
-            // These invalid frame states are expected to be removed
-            // by later compilation stages.
-            FrameState newFrameState = g.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
-            newFrameState.setNodeSourcePosition(fs.getNodeSourcePosition());
-            fs.replaceAndDelete(newFrameState);
-            sawInvalidFrameState = true;
+            if (invalidStateUsers == null) {
+                invalidStateUsers = new ArrayList<>();
+            }
+            for (Node use : fs.usages()) {
+                if (!(use instanceof StateSplit)) {
+                    throw new GraalError("Expected StateSplit for return mismatch");
+                }
+                invalidStateUsers.add((StateSplit) use);
+            }
         }
     }
 
@@ -999,6 +1031,11 @@
                 beginNode.safeDelete();
             }
         }
+        if (graph.isOSR() && getParent() == null && graph.getNodes().filter(EntryMarkerNode.class).isEmpty()) {
+            // This should generally be a transient condition because of inconsistent profile
+            // information.
+            throw new RetryableBailoutException("OSR entry point wasn't parsed");
+        }
     }
 
     /**
@@ -1734,10 +1771,7 @@
             return null;
         }
 
-        JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass());
-        if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) {
-            returnType = returnType.resolve(targetMethod.getDeclaringClass());
-        }
+        JavaType returnType = maybeEagerlyResolve(targetMethod.getSignature().getReturnType(method.getDeclaringClass()), targetMethod.getDeclaringClass());
         if (invokeKind.hasReceiver()) {
             args[0] = maybeEmitExplicitNullCheck(args[0]);
         }
@@ -1763,8 +1797,8 @@
                 return null;
             }
 
-            if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue(options) && !GeneratePIC.getValue(options))) {
-                if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) {
+            if (!invokeKind.isIndirect()) {
+                if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType)) {
                     if (TraceParserPlugins.getValue(options)) {
                         traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)"));
                     }
@@ -2040,184 +2074,8 @@
         }
     }
 
-    protected static class IntrinsicGuard {
-        final FixedWithNextNode lastInstr;
-        final Mark mark;
-        final AbstractBeginNode nonIntrinsicBranch;
-        final ValueNode receiver;
-        final JavaTypeProfile profile;
-
-        public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark, AbstractBeginNode nonIntrinsicBranch, JavaTypeProfile profile) {
-            this.lastInstr = lastInstr;
-            this.receiver = receiver;
-            this.mark = mark;
-            this.nonIntrinsicBranch = nonIntrinsicBranch;
-            this.profile = profile;
-        }
-    }
-
-    /**
-     * Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod}
-     * and not another method that overrides it. This should only be called if there is an
-     * {@link InvocationPlugin} for {@code targetMethod} and the invocation is indirect.
-     *
-     * The control flow woven around the intrinsic is as follows:
-     *
-     * <pre>
-     *  if (LoadMethod(LoadHub(receiver)) == targetMethod) {
-     *       <intrinsic for targetMethod>
-     *  } else {
-     *       <virtual call to targetMethod>
-     *  }
-     * </pre>
-     *
-     * The {@code else} branch is woven by {@link #afterInvocationPluginExecution}.
-     *
-     * @return {@code null} if the intrinsic cannot be used otherwise an object to be used by
-     *         {@link #afterInvocationPluginExecution} to weave code for the non-intrinsic branch
-     */
-    protected IntrinsicGuard guardIntrinsic(ValueNode[] args, ResolvedJavaMethod targetMethod, InvocationPluginReceiver pluginReceiver) {
-        ValueNode intrinsicReceiver = args[0];
-        ResolvedJavaType receiverType = StampTool.typeOrNull(intrinsicReceiver);
-        if (receiverType == null) {
-            // The verifier guarantees it to be at least type declaring targetMethod
-            receiverType = targetMethod.getDeclaringClass();
-        }
-        ResolvedJavaMethod resolvedMethod = receiverType.resolveMethod(targetMethod, method.getDeclaringClass());
-        if (resolvedMethod == null || resolvedMethod.equals(targetMethod)) {
-            assert resolvedMethod == null || targetMethod.getDeclaringClass().isAssignableFrom(resolvedMethod.getDeclaringClass());
-            Mark mark = graph.getMark();
-            FixedWithNextNode currentLastInstr = lastInstr;
-            ValueNode nonNullReceiver = pluginReceiver.get();
-            Stamp methodStamp = getStampProvider().createMethodStamp();
-            LoadHubNode hub = graph.unique(new LoadHubNode(getStampProvider(), nonNullReceiver));
-            LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
-            ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
-            LogicNode compare = graph.addOrUniqueWithInputs(
-                            CompareNode.createCompareNode(getConstantReflection(), getMetaAccess(), options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT));
-
-            JavaTypeProfile profile = null;
-            if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
-                profile = profilingInfo.getTypeProfile(bci());
-                if (profile != null) {
-                    JavaTypeProfile newProfile = adjustProfileForInvocationPlugin(profile, targetMethod);
-                    if (newProfile != profile) {
-                        if (newProfile.getTypes().length == 0) {
-                            // All profiled types select the intrinsic so
-                            // emit a fixed guard instead of an if-then-else.
-                            lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false));
-                            return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null);
-                        }
-                    } else {
-                        // No profiled types select the intrinsic so emit a virtual call
-                        return null;
-                    }
-                    profile = newProfile;
-                }
-            }
-
-            AbstractBeginNode intrinsicBranch = graph.add(new BeginNode());
-            AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode());
-            // In the adjustment above, we filter out receiver types that select the intrinsic as
-            // virtual call target. This means the recorded types in the adjusted profile will
-            // definitely not call into the intrinsic. Note that the following branch probability is
-            // still not precise -- the previously-not-recorded receiver types in the original
-            // profile might or might not call into the intrinsic. Yet we accumulate them into the
-            // probability of the intrinsic branch, assuming that the not-recorded types will only
-            // be a small fraction.
-            append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, profile != null ? profile.getNotRecordedProbability() : LIKELY_PROBABILITY));
-            lastInstr = intrinsicBranch;
-            return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile);
-        } else {
-            // Receiver selects an overriding method so emit a virtual call
-            return null;
-        }
-    }
-
-    /**
-     * Adjusts the profile for an indirect invocation of a virtual method for which there is an
-     * intrinsic. The adjustment made by this method is to remove all types from the profile that do
-     * not override {@code targetMethod}.
-     *
-     * @param profile the profile to adjust
-     * @param targetMethod the virtual method for which there is an intrinsic
-     * @return the adjusted profile or the original {@code profile} object if no adjustment was made
-     */
-    protected JavaTypeProfile adjustProfileForInvocationPlugin(JavaTypeProfile profile, ResolvedJavaMethod targetMethod) {
-        if (profile.getTypes().length > 0) {
-            List<ProfiledType> retained = new ArrayList<>();
-            double notRecordedProbability = profile.getNotRecordedProbability();
-            for (ProfiledType ptype : profile.getTypes()) {
-                if (!ptype.getType().resolveMethod(targetMethod, method.getDeclaringClass()).equals(targetMethod)) {
-                    retained.add(ptype);
-                } else {
-                    notRecordedProbability += ptype.getProbability();
-                }
-            }
-            if (!retained.isEmpty()) {
-                if (retained.size() != profile.getTypes().length) {
-                    return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, retained.toArray(new ProfiledType[retained.size()]));
-                }
-            } else {
-                return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, new ProfiledType[0]);
-            }
-        }
-        return profile;
-    }
-
-    /**
-     * Performs any action required after execution of an invocation plugin. This includes
-     * {@linkplain InvocationPluginAssertions#check checking} invocation plugin invariants as well
-     * as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
-     * {@code guard != null}.
-     */
-    protected void afterInvocationPluginExecution(boolean pluginHandledInvoke, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
-                    InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
-        assert assertions.check(pluginHandledInvoke);
-        if (intrinsicGuard != null) {
-            if (pluginHandledInvoke) {
-                if (intrinsicGuard.nonIntrinsicBranch != null) {
-                    // Intrinsic emitted: emit a virtual call to the target method and
-                    // merge it with the intrinsic branch
-                    EndNode intrinsicEnd = append(new EndNode());
-
-                    FrameStateBuilder intrinsicState = null;
-                    FrameStateBuilder nonIntrinisicState = null;
-                    if (resultType != JavaKind.Void) {
-                        intrinsicState = frameState.copy();
-                        frameState.pop(resultType);
-                        nonIntrinisicState = frameState;
-                    }
-
-                    lastInstr = intrinsicGuard.nonIntrinsicBranch;
-                    createNonInlinedInvoke(getActionForInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
-
-                    EndNode nonIntrinsicEnd = append(new EndNode());
-                    AbstractMergeNode mergeNode = graph.add(new MergeNode());
-
-                    mergeNode.addForwardEnd(intrinsicEnd);
-                    if (intrinsicState != null) {
-                        intrinsicState.merge(mergeNode, nonIntrinisicState);
-                        frameState = intrinsicState;
-                    }
-                    mergeNode.addForwardEnd(nonIntrinsicEnd);
-                    mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode));
-
-                    lastInstr = mergeNode;
-                }
-            } else {
-                // Intrinsic was not applied: remove intrinsic guard
-                // and restore the original receiver node in the arguments array
-                intrinsicGuard.lastInstr.setNext(null);
-                GraphUtil.removeNewNodes(graph, intrinsicGuard.mark);
-                lastInstr = intrinsicGuard.lastInstr;
-                args[0] = intrinsicGuard.receiver;
-            }
-        }
-    }
-
     @SuppressWarnings("try")
-    protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
+    protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) {
         InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
         if (plugin != null) {
 
@@ -2227,24 +2085,15 @@
             }
 
             InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args);
-
-            IntrinsicGuard intrinsicGuard = null;
-            if (invokeKind.isIndirect()) {
-                intrinsicGuard = guardIntrinsic(args, targetMethod, pluginReceiver);
-                if (intrinsicGuard == null) {
-                    return false;
-                } else if (intrinsicGuard.nonIntrinsicBranch == null) {
-                    assert lastInstr instanceof FixedGuardNode;
-                }
-            }
+            assert invokeKind.isDirect() : "Cannot apply invocation plugin on an indirect call site.";
 
             InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
             try (DebugCloseable context = openNodeContext(targetMethod)) {
                 if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
-                    afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+                    assert assertions.check(true);
                     return !plugin.isDecorator();
                 } else {
-                    afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+                    assert assertions.check(false);
                 }
             }
         }
@@ -2630,8 +2479,9 @@
         FixedWithNextNode calleeBeforeUnwindNode = null;
         ValueNode calleeUnwindValue = null;
 
-        try (InliningScope s = parsingIntrinsic() ? null : (calleeIntrinsicContext != null ? new IntrinsicScope(this, targetMethod, args)
-                        : new InliningScope(this, targetMethod, args))) {
+        try (InliningScope s = parsingIntrinsic() ? null
+                        : (calleeIntrinsicContext != null ? new IntrinsicScope(this, targetMethod, args)
+                                        : new InliningScope(this, targetMethod, args))) {
             BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
             FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph, graphBuilderConfig.retainLocalVariables());
             if (!targetMethod.isStatic()) {
@@ -2642,7 +2492,6 @@
 
             List<ReturnToCallerData> calleeReturnDataList = parser.returnDataList;
 
-            processCalleeReturn(targetMethod, s, calleeReturnDataList);
             /*
              * Propagate any side effects into the caller when parsing intrinsics.
              */
@@ -2652,6 +2501,8 @@
                 }
             }
 
+            processCalleeReturn(targetMethod, s, calleeReturnDataList);
+
             calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
             if (calleeBeforeUnwindNode != null) {
                 calleeUnwindValue = parser.getUnwindValue();
@@ -2743,7 +2594,7 @@
                 if (stateSplit.hasSideEffect()) {
                     assert stateSplit != null;
                     if (stateAfter.bci == BytecodeFrame.AFTER_BCI) {
-                        assert stateAfter.usages().count() == 1;
+                        assert stateAfter.hasExactlyOneUsage();
                         assert stateAfter.usages().first() == stateSplit;
                         FrameState state;
                         if (returnVal.getStackKind() == JavaKind.Illegal) {
@@ -4233,7 +4084,7 @@
 
     private String unresolvedMethodAssertionMessage(JavaMethod result) {
         String message = result.format("%H.%n(%P)%R");
-        if (JavaVersionUtil.Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             JavaType declaringClass = result.getDeclaringClass();
             String className = declaringClass.getName();
             switch (className) {
@@ -4324,6 +4175,13 @@
         }
     }
 
+    protected JavaType maybeEagerlyResolve(JavaType type, ResolvedJavaType accessingClass) {
+        if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) {
+            return type.resolve(accessingClass);
+        }
+        return type;
+    }
+
     protected void maybeEagerlyInitialize(ResolvedJavaType resolvedType) {
         if (!resolvedType.isInitialized() && eagerInitializing) {
             initialize(resolvedType);
@@ -5350,4 +5208,3 @@
         return n == 0 ? "" : format("%" + n + "s", "");
     }
 }
-
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -66,8 +66,5 @@
 
     @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
     public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);
-
-    @Option(help = "Use intrinsics guarded by a virtual dispatch test at indirect call sites.", type = OptionType.Debug)
-    public static final OptionKey<Boolean> UseGuardedIntrinsics = new OptionKey<>(true);
     // @formatter:on
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,7 +43,6 @@
 
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
-import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -146,7 +145,7 @@
 
         this.monitorIds = EMPTY_MONITOR_ARRAY;
         this.graph = graph;
-        this.clearNonLiveLocals = GraalOptions.OptClearNonLiveLocals.getValue(graph.getOptions()) && !shouldRetainLocalVariables;
+        this.clearNonLiveLocals = !shouldRetainLocalVariables;
         this.canVerifyKind = true;
     }
 
@@ -275,8 +274,6 @@
         clearNonLiveLocals = other.clearNonLiveLocals;
         monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
 
-        assert locals.length == code.getMaxLocals();
-        assert stack.length == Math.max(1, code.getMaxStackSize());
         assert lockedObjects.length == monitorIds.length;
     }
 
@@ -791,7 +788,7 @@
     public ValueNode pop(JavaKind slotKind) {
         if (slotKind.needsTwoSlots()) {
             ValueNode s = xpop();
-            assert s == TWO_SLOT_MARKER;
+            assert s == TWO_SLOT_MARKER : s;
         }
         ValueNode x = xpop();
         assert verifyKind(slotKind, x);
@@ -835,7 +832,7 @@
                 /* Ignore second slot of two-slot value. */
                 x = xpop();
             }
-            assert x != null && x != TWO_SLOT_MARKER;
+            assert x != null && x != TWO_SLOT_MARKER : x;
             result[i] = x;
         }
         return result;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,6 +26,7 @@
 
 import org.graalvm.compiler.jtt.JTTTest;
 import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -37,7 +38,7 @@
      * Tests a unary {@link Math} method on a wide range of values.
      */
     void testManyValues(OptionValues options, ResolvedJavaMethod method) throws AssertionError {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             /*
              * GR-8276: Allow for variance on JVMCI > 8 until a JVMCI version that includes
              * https://github.com/graalvm/graal-jvmci-8/commit/
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java	Fri Jun 28 14:36:42 2019 +0530
@@ -129,8 +129,7 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         assert graph.getNodes().filter(CommitAllocationNode.class).count() == 0 : "all allocations should be virtualized";
-        return true;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyFloats.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/*
+ * Tests comparison-based canonicalizations for floats.
+ */
+@RunWith(Parameterized.class)
+public class TrichotomyFloats extends JTTTest {
+
+    public static int test0(float x, float y) {
+        return x < y ? -1 : (x == y ? 0 : 1);
+    }
+
+    public static int test1(float x, float y) {
+        return x < y ? 1 : (x == y ? 0 : -1);
+    }
+
+    public static int test2(float x, float y) {
+        return x == y ? 0 : (x < y ? -1 : 1);
+    }
+
+    public static int test3(float x, float y) {
+        return x == y ? 0 : (x < y ? 1 : -1);
+    }
+
+    public static int test4(float x, float y) {
+        return x == y ? 0 : (x > y ? -1 : 1);
+    }
+
+    public static int test5(float x, float y) {
+        return x == y ? 0 : (x > y ? 1 : -1);
+    }
+
+    public static int test6(float x, float y) {
+        return x < y ? 1 : (x > y ? -1 : 0);
+    }
+
+    public static int test7(float x, float y) {
+        return x < y ? -1 : (x > y ? 1 : 0);
+    }
+
+    @Parameter(value = 0) public float x;
+    @Parameter(value = 1) public float y;
+
+    @Parameters(name = "x = {0}, y = {1}")
+    public static Collection<Object[]> data() {
+        List<Object[]> parameters = new ArrayList<>();
+        float[] floats = {Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN, 0f, -1f, Float.MIN_VALUE, Float.MAX_VALUE};
+        for (float f1 : floats) {
+            for (float f2 : floats) {
+                parameters.add(new Object[]{f1, f2});
+            }
+        }
+        return parameters;
+    }
+
+    @Test
+    public void run0() {
+        runTest("test0", x, y);
+    }
+
+    @Test
+    public void run1() {
+        runTest("test1", x, y);
+    }
+
+    @Test
+    public void run2() {
+        runTest("test2", x, y);
+    }
+
+    @Test
+    public void run3() {
+        runTest("test3", x, y);
+    }
+
+    @Test
+    public void run4() {
+        runTest("test4", x, y);
+    }
+
+    @Test
+    public void run5() {
+        runTest("test5", x, y);
+    }
+
+    @Test
+    public void run6() {
+        runTest("test6", x, y);
+    }
+
+    @Test
+    public void run7() {
+        runTest("test7", x, y);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64BitFieldOp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Arm Limited and affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.lir.aarch64;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+
+/**
+ * Bit field ops for AArch64.
+ */
+public class AArch64BitFieldOp extends AArch64LIRInstruction {
+    public enum BitFieldOpCode {
+        UBFX,
+        UBFIZ,
+    }
+
+    private static final LIRInstructionClass<AArch64BitFieldOp> TYPE = LIRInstructionClass.create(AArch64BitFieldOp.class);
+
+    @Opcode private final AArch64BitFieldOp.BitFieldOpCode opcode;
+    @Def protected AllocatableValue result;
+    @Use({REG}) protected AllocatableValue input;
+    private final int lsb;
+    private final int width;
+
+    public AArch64BitFieldOp(AArch64BitFieldOp.BitFieldOpCode opcode, AllocatableValue result,
+                    AllocatableValue input, int lsb, int width) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+        this.lsb = lsb;
+        this.width = width;
+    }
+
+    @Override
+    protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register dst = asRegister(result);
+        Register src = asRegister(input);
+        final int size = input.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        switch (opcode) {
+            case UBFX:
+                masm.ubfm(size, dst, src, lsb, lsb + width - 1);
+                break;
+            case UBFIZ:
+                masm.ubfm(size, dst, src, size - lsb, width - 1);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java	Fri Jun 28 14:36:42 2019 +0530
@@ -433,7 +433,10 @@
     }
 
     static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
-        AArch64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL);
+        AArch64Address dest;
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            dest = loadStackSlotAddress(crb, masm, asStackSlot(result), scratch.getRegister());
+        }
         Register src = asRegister(input);
         // use the slot kind to define the operand size
         AArch64Kind kind = (AArch64Kind) result.getPlatformKind();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -48,6 +48,7 @@
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 
 import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 
@@ -79,10 +80,10 @@
     @Alive({REG}) private Value array1Value;
     @Alive({REG}) private Value array2Value;
     @Alive({REG}) private Value lengthValue;
-    @Temp({REG}) private Value temp1;
-    @Temp({REG}) private Value temp2;
+    @Temp({REG, ILLEGAL}) private Value temp1;
+    @Temp({REG, ILLEGAL}) private Value temp2;
     @Temp({REG}) private Value temp3;
-    @Temp({REG}) private Value temp4;
+    @Temp({REG, ILLEGAL}) private Value temp4;
 
     @Temp({REG, ILLEGAL}) private Value temp5;
     @Temp({REG, ILLEGAL}) private Value tempXMM;
@@ -114,12 +115,22 @@
         this.lengthValue = length;
 
         // Allocate some temporaries.
-        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
-        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        if (supportsSSE41(tool.target()) && canGenerateConstantLengthCompare(tool.target()) && !constantLengthCompareNeedsTmpArrayPointers()) {
+            this.temp1 = Value.ILLEGAL;
+            this.temp2 = Value.ILLEGAL;
+        } else {
+            this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+            this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        }
         this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
-        this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+        if (supportsSSE41(tool.target()) && canGenerateConstantLengthCompare(tool.target())) {
+            this.temp4 = Value.ILLEGAL;
+            this.temp5 = Value.ILLEGAL;
+        } else {
+            this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+            this.temp5 = kind1.isNumericFloat() || kind1 != kind2 ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL;
+        }
 
-        this.temp5 = kind1.isNumericFloat() || kind1 != kind2 ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL;
         if (kind1 == JavaKind.Float) {
             this.tempXMM = tool.newVariable(LIRKind.value(AMD64Kind.SINGLE));
         } else if (kind1 == JavaKind.Double) {
@@ -157,21 +168,19 @@
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         Register result = asRegister(resultValue);
-        Register array1 = asRegister(temp1);
-        Register array2 = asRegister(temp2);
 
         Label trueLabel = new Label();
         Label falseLabel = new Label();
         Label done = new Label();
 
-        // Load array base addresses.
-        masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset1));
-        masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset2));
-
         if (canGenerateConstantLengthCompare(crb.target)) {
-            emitConstantLengthArrayCompareBytes(crb, masm, array1, array2, asRegister(temp3), asRegister(temp4),
-                            new Register[]{asRegister(vectorTemp1), asRegister(vectorTemp2), asRegister(vectorTemp3), asRegister(vectorTemp4)}, falseLabel);
+            emitConstantLengthArrayCompareBytes(crb, masm, new Register[]{asRegister(vectorTemp1), asRegister(vectorTemp2), asRegister(vectorTemp3), asRegister(vectorTemp4)}, falseLabel);
         } else {
+            Register array1 = asRegister(temp1);
+            Register array2 = asRegister(temp2);
+            // Load array base addresses.
+            masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset1));
+            masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset2));
             Register length = asRegister(temp3);
             // Get array length.
             masm.movl(length, asRegister(lengthValue));
@@ -705,6 +714,15 @@
         masm.subq(index, range);
     }
 
+    private boolean constantLengthCompareNeedsTmpArrayPointers() {
+        AVXKind.AVXSize vSize = vectorSize;
+        if (constantLength < getElementsPerVector(vectorSize)) {
+            vSize = AVXKind.AVXSize.XMM;
+        }
+        int vectorCount = constantLength & ~(2 * getElementsPerVector(vSize) - 1);
+        return vectorCount > 0;
+    }
+
     /**
      * Emits specialized assembly for checking equality of memory regions
      * {@code arrayPtr1[0..nBytes]} and {@code arrayPtr2[0..nBytes]}. If they match, execution
@@ -713,16 +731,15 @@
     private void emitConstantLengthArrayCompareBytes(
                     CompilationResultBuilder crb,
                     AMD64MacroAssembler asm,
-                    Register arrayPtr1,
-                    Register arrayPtr2,
-                    Register tmp1,
-                    Register tmp2,
                     Register[] tmpVectors,
                     Label noMatch) {
         if (constantLength == 0) {
             // do nothing
             return;
         }
+        Register arrayPtr1 = asRegister(array1Value);
+        Register arrayPtr2 = asRegister(array2Value);
+        Register tmp = asRegister(temp3);
         AVXKind.AVXSize vSize = vectorSize;
         if (constantLength < getElementsPerVector(vectorSize)) {
             vSize = AVXKind.AVXSize.XMM;
@@ -731,17 +748,15 @@
         if (elementsPerVector > constantLength) {
             assert kind1 == kind2;
             int byteLength = constantLength << arrayIndexScale1.log2;
-            // array is shorter than any vector register, use regular CMP instructions
+            // array is shorter than any vector register, use regular XOR instructions
             int movSize = (byteLength < 2) ? 1 : ((byteLength < 4) ? 2 : ((byteLength < 8) ? 4 : 8));
-            emitMovBytes(asm, tmp1, new AMD64Address(arrayPtr1), movSize);
-            emitMovBytes(asm, tmp2, new AMD64Address(arrayPtr2), movSize);
-            emitCmpBytes(asm, tmp1, tmp2, movSize);
-            asm.jcc(AMD64Assembler.ConditionFlag.NotEqual, noMatch);
+            emitMovBytes(asm, tmp, new AMD64Address(arrayPtr1, arrayBaseOffset1), movSize);
+            emitXorBytes(asm, tmp, new AMD64Address(arrayPtr2, arrayBaseOffset2), movSize);
+            asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
             if (byteLength > movSize) {
-                emitMovBytes(asm, tmp1, new AMD64Address(arrayPtr1, byteLength - movSize), movSize);
-                emitMovBytes(asm, tmp2, new AMD64Address(arrayPtr2, byteLength - movSize), movSize);
-                emitCmpBytes(asm, tmp1, tmp2, movSize);
-                asm.jcc(AMD64Assembler.ConditionFlag.NotEqual, noMatch);
+                emitMovBytes(asm, tmp, new AMD64Address(arrayPtr1, arrayBaseOffset1 + byteLength - movSize), movSize);
+                emitXorBytes(asm, tmp, new AMD64Address(arrayPtr2, arrayBaseOffset2 + byteLength - movSize), movSize);
+                asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
             }
         } else {
             int elementsPerVectorLoop = 2 * elementsPerVector;
@@ -750,37 +765,41 @@
             int bytesPerVector = vSize.getBytes();
             if (vectorCount > 0) {
                 Label loopBegin = new Label();
-                asm.leaq(arrayPtr1, new AMD64Address(arrayPtr1, vectorCount << arrayIndexScale1.log2));
-                asm.leaq(arrayPtr2, new AMD64Address(arrayPtr2, vectorCount << arrayIndexScale2.log2));
-                asm.movq(tmp1, -vectorCount);
+                Register tmpArrayPtr1 = asRegister(temp1);
+                Register tmpArrayPtr2 = asRegister(temp2);
+                asm.leaq(tmpArrayPtr1, new AMD64Address(arrayPtr1, vectorCount << arrayIndexScale1.log2));
+                asm.leaq(tmpArrayPtr2, new AMD64Address(arrayPtr2, vectorCount << arrayIndexScale2.log2));
+                arrayPtr1 = tmpArrayPtr1;
+                arrayPtr2 = tmpArrayPtr2;
+                asm.movq(tmp, -vectorCount);
                 asm.align(crb.target.wordSize * 2);
                 asm.bind(loopBegin);
-                emitVectorLoad1(asm, tmpVectors[0], arrayPtr1, tmp1, 0, vSize);
-                emitVectorLoad2(asm, tmpVectors[1], arrayPtr2, tmp1, 0, vSize);
-                emitVectorLoad1(asm, tmpVectors[2], arrayPtr1, tmp1, scaleDisplacement1(bytesPerVector), vSize);
-                emitVectorLoad2(asm, tmpVectors[3], arrayPtr2, tmp1, scaleDisplacement2(bytesPerVector), vSize);
+                emitVectorLoad1(asm, tmpVectors[0], arrayPtr1, tmp, arrayBaseOffset1, vSize);
+                emitVectorLoad2(asm, tmpVectors[1], arrayPtr2, tmp, arrayBaseOffset2, vSize);
+                emitVectorLoad1(asm, tmpVectors[2], arrayPtr1, tmp, arrayBaseOffset1 + scaleDisplacement1(bytesPerVector), vSize);
+                emitVectorLoad2(asm, tmpVectors[3], arrayPtr2, tmp, arrayBaseOffset2 + scaleDisplacement2(bytesPerVector), vSize);
                 emitVectorXor(asm, tmpVectors[0], tmpVectors[1], vSize);
                 emitVectorXor(asm, tmpVectors[2], tmpVectors[3], vSize);
                 emitVectorTest(asm, tmpVectors[0], vSize);
-                asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch);
+                asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
                 emitVectorTest(asm, tmpVectors[2], vSize);
-                asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch);
-                asm.addq(tmp1, elementsPerVectorLoop);
-                asm.jcc(AMD64Assembler.ConditionFlag.NotZero, loopBegin);
+                asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
+                asm.addq(tmp, elementsPerVectorLoop);
+                asm.jccb(AMD64Assembler.ConditionFlag.NotZero, loopBegin);
             }
             if (tailCount > 0) {
-                emitVectorLoad1(asm, tmpVectors[0], arrayPtr1, (tailCount << arrayIndexScale1.log2) - scaleDisplacement1(bytesPerVector), vSize);
-                emitVectorLoad2(asm, tmpVectors[1], arrayPtr2, (tailCount << arrayIndexScale2.log2) - scaleDisplacement2(bytesPerVector), vSize);
+                emitVectorLoad1(asm, tmpVectors[0], arrayPtr1, arrayBaseOffset1 + (tailCount << arrayIndexScale1.log2) - scaleDisplacement1(bytesPerVector), vSize);
+                emitVectorLoad2(asm, tmpVectors[1], arrayPtr2, arrayBaseOffset2 + (tailCount << arrayIndexScale2.log2) - scaleDisplacement2(bytesPerVector), vSize);
                 emitVectorXor(asm, tmpVectors[0], tmpVectors[1], vSize);
                 if (tailCount > elementsPerVector) {
-                    emitVectorLoad1(asm, tmpVectors[2], arrayPtr1, 0, vSize);
-                    emitVectorLoad2(asm, tmpVectors[3], arrayPtr2, 0, vSize);
+                    emitVectorLoad1(asm, tmpVectors[2], arrayPtr1, arrayBaseOffset1, vSize);
+                    emitVectorLoad2(asm, tmpVectors[3], arrayPtr2, arrayBaseOffset2, vSize);
                     emitVectorXor(asm, tmpVectors[2], tmpVectors[3], vSize);
                     emitVectorTest(asm, tmpVectors[2], vSize);
-                    asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch);
+                    asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
                 }
                 emitVectorTest(asm, tmpVectors[0], vSize);
-                asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch);
+                asm.jccb(AMD64Assembler.ConditionFlag.NotZero, noMatch);
             }
         }
     }
@@ -817,11 +836,23 @@
         }
     }
 
-    private static void emitCmpBytes(AMD64MacroAssembler asm, Register dst, Register src, int size) {
-        if (size < 8) {
-            asm.cmpl(dst, src);
-        } else {
-            asm.cmpq(dst, src);
+    private static void emitXorBytes(AMD64MacroAssembler asm, Register dst, AMD64Address src, int size) {
+        OperandSize opSize = getOperandSize(size);
+        XOR.getRMOpcode(opSize).emit(asm, opSize, dst, src);
+    }
+
+    private static OperandSize getOperandSize(int size) {
+        switch (size) {
+            case 1:
+                return OperandSize.BYTE;
+            case 2:
+                return OperandSize.WORD;
+            case 4:
+                return OperandSize.DWORD;
+            case 8:
+                return OperandSize.QWORD;
+            default:
+                throw new IllegalStateException();
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,30 +24,43 @@
 
 package org.graalvm.compiler.lir.amd64;
 
-import jdk.vm.ci.amd64.AMD64;
-import jdk.vm.ci.amd64.AMD64.CPUFeature;
-import jdk.vm.ci.amd64.AMD64Kind;
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Value;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.util.Objects;
+
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMoveOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRMIOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRMOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp;
+import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
 import org.graalvm.compiler.asm.amd64.AVXKind;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
+import org.graalvm.compiler.lir.ConstantValue;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.Opcode;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
-import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
 
 /**
  */
@@ -55,24 +68,23 @@
 public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction {
     public static final LIRInstructionClass<AMD64ArrayIndexOfOp> TYPE = LIRInstructionClass.create(AMD64ArrayIndexOfOp.class);
 
-    private final JavaKind kind;
-    private final int vmPageSize;
+    private final JavaKind valueKind;
     private final int nValues;
     private final boolean findTwoConsecutive;
     private final AMD64Kind vectorKind;
+    private final int arrayBaseOffset;
+    private final Scale arrayIndexScale;
 
     @Def({REG}) protected Value resultValue;
     @Alive({REG}) protected Value arrayPtrValue;
-    @Use({REG}) protected Value arrayLengthValue;
-    @Alive({REG}) protected Value searchValue1;
-    @Alive({REG, ILLEGAL}) protected Value searchValue2;
-    @Alive({REG, ILLEGAL}) protected Value searchValue3;
-    @Alive({REG, ILLEGAL}) protected Value searchValue4;
-    @Temp({REG}) protected Value arraySlotsRemaining;
+    @Alive({REG}) protected Value arrayLengthValue;
+    @Use({REG}) protected Value fromIndexValue;
+    @Alive({REG, STACK, CONST}) protected Value searchValue1;
+    @Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue2;
+    @Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue3;
+    @Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue4;
     @Temp({REG}) protected Value comparisonResult1;
-    @Temp({REG}) protected Value comparisonResult2;
-    @Temp({REG}) protected Value comparisonResult3;
-    @Temp({REG}) protected Value comparisonResult4;
+    @Temp({REG, ILLEGAL}) protected Value comparisonResult2;
     @Temp({REG, ILLEGAL}) protected Value vectorCompareVal1;
     @Temp({REG, ILLEGAL}) protected Value vectorCompareVal2;
     @Temp({REG, ILLEGAL}) protected Value vectorCompareVal3;
@@ -82,31 +94,30 @@
     @Temp({REG, ILLEGAL}) protected Value vectorArray3;
     @Temp({REG, ILLEGAL}) protected Value vectorArray4;
 
-    public AMD64ArrayIndexOfOp(JavaKind kind, boolean findTwoConsecutive, int vmPageSize, int maxVectorSize, LIRGeneratorTool tool, Value result, Value arrayPtr, Value arrayLength,
-                    Value... searchValues) {
+    public AMD64ArrayIndexOfOp(JavaKind arrayKind, JavaKind valueKind, boolean findTwoConsecutive, int maxVectorSize, LIRGeneratorTool tool,
+                    Value result, Value arrayPtr, Value arrayLength, Value fromIndex, Value... searchValues) {
         super(TYPE);
-        this.kind = kind;
+        this.valueKind = valueKind;
+        this.arrayBaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(arrayKind);
+        this.arrayIndexScale = Objects.requireNonNull(Scale.fromInt(tool.getProviders().getMetaAccess().getArrayIndexScale(valueKind)));
         this.findTwoConsecutive = findTwoConsecutive;
-        this.vmPageSize = vmPageSize;
         assert 0 < searchValues.length && searchValues.length <= 4;
-        assert byteMode(kind) || charMode(kind);
+        assert byteMode(valueKind) || charMode(valueKind);
         assert supports(tool, CPUFeature.SSE2) || supports(tool, CPUFeature.AVX) || supportsAVX2(tool);
         nValues = searchValues.length;
         assert !findTwoConsecutive || nValues == 1;
         resultValue = result;
         arrayPtrValue = arrayPtr;
         arrayLengthValue = arrayLength;
+        fromIndexValue = fromIndex;
         searchValue1 = searchValues[0];
         searchValue2 = nValues > 1 ? searchValues[1] : Value.ILLEGAL;
         searchValue3 = nValues > 2 ? searchValues[2] : Value.ILLEGAL;
         searchValue4 = nValues > 3 ? searchValues[3] : Value.ILLEGAL;
-        arraySlotsRemaining = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
-        comparisonResult1 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
-        comparisonResult2 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
-        comparisonResult3 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
-        comparisonResult4 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
-        vectorKind = supportsAVX2(tool) && (maxVectorSize < 0 || maxVectorSize >= 32) ? byteMode(kind) ? AMD64Kind.V256_BYTE : AMD64Kind.V256_WORD
-                        : byteMode(kind) ? AMD64Kind.V128_BYTE : AMD64Kind.V128_WORD;
+        comparisonResult1 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
+        comparisonResult2 = findTwoConsecutive ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL;
+        vectorKind = supportsAVX2(tool) && (maxVectorSize < 0 || maxVectorSize >= 32) ? byteMode(valueKind) ? AMD64Kind.V256_BYTE : AMD64Kind.V256_WORD
+                        : byteMode(valueKind) ? AMD64Kind.V128_BYTE : AMD64Kind.V128_WORD;
         vectorCompareVal1 = tool.newVariable(LIRKind.value(vectorKind));
         vectorCompareVal2 = nValues > 1 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL;
         vectorCompareVal3 = nValues > 2 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL;
@@ -126,7 +137,7 @@
     }
 
     private JavaKind getComparisonKind() {
-        return findTwoConsecutive ? (byteMode(kind) ? JavaKind.Char : JavaKind.Int) : kind;
+        return findTwoConsecutive ? (byteMode(valueKind) ? JavaKind.Char : JavaKind.Int) : valueKind;
     }
 
     private AVXKind.AVXSize getVectorSize() {
@@ -135,15 +146,16 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1;
         Register arrayPtr = asRegister(arrayPtrValue);
         Register arrayLength = asRegister(arrayLengthValue);
-        Register result = asRegister(resultValue);
-        Register slotsRemaining = asRegister(arraySlotsRemaining);
-        Register[] searchValue = {
-                        nValues > 0 ? asRegister(searchValue1) : null,
-                        nValues > 1 ? asRegister(searchValue2) : null,
-                        nValues > 2 ? asRegister(searchValue3) : null,
-                        nValues > 3 ? asRegister(searchValue4) : null,
+        Register fromIndex = asRegister(fromIndexValue);
+        Register index = asRegister(resultValue);
+        Value[] searchValue = {
+                        nValues > 0 ? searchValue1 : null,
+                        nValues > 1 ? searchValue2 : null,
+                        nValues > 2 ? searchValue3 : null,
+                        nValues > 3 ? searchValue4 : null,
         };
         Register[] vecCmp = {
                         nValues > 0 ? asRegister(vectorCompareVal1) : null,
@@ -159,60 +171,9 @@
         };
         Register[] cmpResult = {
                         asRegister(comparisonResult1),
-                        asRegister(comparisonResult2),
-                        asRegister(comparisonResult3),
-                        asRegister(comparisonResult4),
+                        findTwoConsecutive ? asRegister(comparisonResult2) : null,
         };
-        Label retFound = new Label();
-        Label retNotFound = new Label();
-        Label end = new Label();
-
-        // load array length
-        // important: this must be the first register manipulation, since arrayLengthValue is
-        // annotated with @Use
-        asm.movl(slotsRemaining, arrayLength);
-        // load array pointer
-        asm.movq(result, arrayPtr);
-        // move search values to vectors
-        for (int i = 0; i < nValues; i++) {
-            if (asm.supports(CPUFeature.AVX)) {
-                VexMoveOp.VMOVD.emit(asm, AVXKind.AVXSize.DWORD, vecCmp[i], searchValue[i]);
-            } else {
-                asm.movdl(vecCmp[i], searchValue[i]);
-            }
-        }
-        // fill comparison vector with copies of the search value
-        for (int i = 0; i < nValues; i++) {
-            emitBroadcast(asm, getComparisonKind(), vecCmp[i], vecArray[0], getVectorSize());
-        }
-
-        emitArrayIndexOfChars(crb, asm, result, slotsRemaining, searchValue, vecCmp, vecArray, cmpResult, retFound, retNotFound);
-
-        // return -1 (no match)
-        asm.bind(retNotFound);
-        asm.movq(result, -1);
-        asm.jmpb(end);
-
-        asm.bind(retFound);
-        // convert array pointer to offset
-        asm.subq(result, arrayPtr);
-        if (charMode(kind)) {
-            asm.shrq(result, 1);
-        }
-        asm.bind(end);
-    }
-
-    private void emitArrayIndexOfChars(CompilationResultBuilder crb, AMD64MacroAssembler asm,
-                    Register arrayPtr,
-                    Register slotsRemaining,
-                    Register[] searchValue,
-                    Register[] vecCmp,
-                    Register[] vecArray,
-                    Register[] cmpResult,
-                    Label retFound,
-                    Label retNotFound) {
-        int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1;
-        AVXKind.AVXSize vectorSize = getVectorSize();
+        Label ret = new Label();
 
         Label bulkVectorLoop = new Label();
         Label singleVectorLoop = new Label();
@@ -222,225 +183,276 @@
                         new Label(),
                         new Label(),
         };
-        Label lessThanVectorSizeRemaining = new Label();
-        Label lessThanVectorSizeRemainingLoop = new Label();
-        Label bulkVectorLoopExit = nVectors == 1 ? lessThanVectorSizeRemaining : singleVectorLoop;
-        int bytesPerVector = vectorSize.getBytes();
-        int arraySlotsPerVector = vectorSize.getBytes() / kind.getByteCount();
-        int singleVectorLoopCondition = arraySlotsPerVector;
-        int bulkSize = arraySlotsPerVector * nVectors;
-        int bulkSizeBytes = bytesPerVector * nVectors;
-        int bulkLoopCondition = bulkSize;
-        int[] vectorOffsets;
-        JavaKind vectorCompareKind = kind;
+        Label runVectorized = new Label();
+        Label elementWiseLoop = new Label();
+        Label elementWiseFound = new Label();
+        Label elementWiseNotFound = new Label();
+        Label skipBulkVectorLoop = new Label();
+        int vectorSize = getVectorSize().getBytes() / valueKind.getByteCount();
+        int bulkSize = vectorSize * nVectors;
+        JavaKind vectorCompareKind = valueKind;
         if (findTwoConsecutive) {
-            singleVectorLoopCondition++;
-            bulkLoopCondition++;
             bulkSize /= 2;
-            bulkSizeBytes /= 2;
-            vectorOffsets = new int[]{0, kind.getByteCount(), bytesPerVector, bytesPerVector + kind.getByteCount()};
-            vectorCompareKind = byteMode(kind) ? JavaKind.Char : JavaKind.Int;
+            vectorCompareKind = byteMode(valueKind) ? JavaKind.Char : JavaKind.Int;
+        }
+        // index = fromIndex + vectorSize (+1 if findTwoConsecutive)
+        // important: this must be the first register manipulation, since fromIndex is
+        // annotated with @Use
+        asm.leaq(index, new AMD64Address(fromIndex, vectorSize + (findTwoConsecutive ? 1 : 0)));
+
+        // check if vector vector load is in bounds
+        asm.cmpq(index, arrayLength);
+        asm.jccb(AMD64Assembler.ConditionFlag.LessEqual, runVectorized);
+
+        // search range is smaller than vector size, do element-wise comparison
+
+        // index = fromIndex (+ 1 if findTwoConsecutive)
+        asm.subq(index, vectorSize);
+        // check if enough array slots remain
+        asm.cmpq(index, arrayLength);
+        asm.jccb(AMD64Assembler.ConditionFlag.GreaterEqual, elementWiseNotFound);
+        // compare one-by-one
+        asm.bind(elementWiseLoop);
+        // check for match
+        OperandSize cmpSize = getOpSize(getComparisonKind());
+        // address = findTwoConsecutive ? array[index - 1] : array[index]
+        AMD64Address arrayAddr = new AMD64Address(arrayPtr, index, arrayIndexScale, arrayBaseOffset - (findTwoConsecutive ? valueKind.getByteCount() : 0));
+        boolean valuesOnStack = searchValuesOnStack(searchValue);
+        if (valuesOnStack) {
+            (cmpSize == OperandSize.BYTE ? AMD64RMOp.MOVB : AMD64RMOp.MOV).emit(asm, cmpSize, cmpResult[0], arrayAddr);
+            for (int i = 0; i < nValues; i++) {
+                if (isConstant(searchValue[i])) {
+                    int imm = asConstant(searchValue[i]).asInt();
+                    AMD64Assembler.AMD64BinaryArithmetic.CMP.getMIOpcode(cmpSize, NumUtil.isByte(imm)).emit(asm, cmpSize, cmpResult[0], imm);
+                } else if (isStackSlot(searchValue[i])) {
+                    AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, cmpResult[0], (AMD64Address) crb.asAddress(searchValue[i]));
+                } else {
+                    AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, cmpResult[0], asRegister(searchValue[i]));
+                }
+                asm.jccb(AMD64Assembler.ConditionFlag.Equal, elementWiseFound);
+            }
         } else {
-            vectorOffsets = new int[]{0, bytesPerVector, bytesPerVector * 2, bytesPerVector * 3};
+            for (int i = 0; i < nValues; i++) {
+                if (isConstant(searchValue[i])) {
+                    int imm = asConstant(searchValue[i]).asInt();
+                    AMD64Assembler.AMD64BinaryArithmetic.CMP.getMIOpcode(cmpSize, NumUtil.isByte(imm)).emit(asm, cmpSize, arrayAddr, imm);
+                } else {
+                    AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, asRegister(searchValue[i]), arrayAddr);
+                }
+                asm.jccb(AMD64Assembler.ConditionFlag.Equal, elementWiseFound);
+            }
+        }
+        // adjust index
+        asm.incrementq(index, 1);
+        // continue loop
+        asm.cmpq(index, arrayLength);
+        asm.jccb(AMD64Assembler.ConditionFlag.Less, elementWiseLoop);
+
+        asm.bind(elementWiseNotFound);
+        asm.xorq(index, index);
+
+        if (findTwoConsecutive) {
+            asm.bind(elementWiseFound);
+            asm.decrementq(index, 1);
+        } else {
+            asm.decrementq(index, 1);
+            asm.bind(elementWiseFound);
+        }
+        asm.jmp(ret);
+
+        // vectorized implementation
+        asm.bind(runVectorized);
+
+        // move search values to vectors
+        for (int i = 0; i < nValues; i++) {
+            // fill comparison vector with copies of the search value
+            broadcastSearchValue(crb, asm, vecCmp[i], searchValue[i], cmpResult[0], vecArray[0]);
         }
 
-        // load copy of low part of array pointer
-        Register tmpArrayPtrLow = cmpResult[0];
-        asm.movl(tmpArrayPtrLow, arrayPtr);
-
-        // check if bulk vector load is in bounds
-        asm.cmpl(slotsRemaining, bulkLoopCondition);
-        asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit);
-
-        // check if array pointer is aligned to bulkSize
-        asm.andl(tmpArrayPtrLow, bulkSizeBytes - 1);
-        asm.jcc(AMD64Assembler.ConditionFlag.Zero, bulkVectorLoop);
+        // do one unaligned vector comparison pass and adjust alignment afterwards
+        emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, false, false);
 
-        // do one unaligned bulk comparison pass and adjust alignment afterwards
-        emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false);
-        // load copy of low part of array pointer
-        asm.movl(tmpArrayPtrLow, arrayPtr);
-        // adjust array pointer
-        asm.addq(arrayPtr, bulkSizeBytes);
-        // adjust number of array slots remaining
-        asm.subl(slotsRemaining, bulkSize);
-        // get offset to bulk size alignment
-        asm.andl(tmpArrayPtrLow, bulkSizeBytes - 1);
-        emitBytesToArraySlots(asm, kind, tmpArrayPtrLow);
-        // adjust array pointer to bulk size alignment
-        asm.andq(arrayPtr, ~(bulkSizeBytes - 1));
-        // adjust number of array slots remaining
-        asm.addl(slotsRemaining, tmpArrayPtrLow);
+        // adjust index to vector size alignment
+        asm.leaq(cmpResult[0], new AMD64Address(arrayPtr, arrayBaseOffset));
+        if (charMode(valueKind)) {
+            asm.shrq(cmpResult[0], 1);
+        }
+        asm.addq(index, cmpResult[0]);
+        // adjust to next lower multiple of vector size
+        asm.andq(index, ~(vectorSize - 1));
+        asm.subq(index, cmpResult[0]);
+        // add bulk size
+        asm.addq(index, bulkSize);
+
         // check if there are enough array slots remaining for the bulk loop
-        asm.cmpl(slotsRemaining, bulkLoopCondition);
-        asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit);
+        asm.cmpq(index, arrayLength);
+        asm.jccb(AMD64Assembler.ConditionFlag.Greater, skipBulkVectorLoop);
 
         emitAlign(crb, asm);
         asm.bind(bulkVectorLoop);
         // memory-aligned bulk comparison
-        emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, !findTwoConsecutive);
-        // adjust number of array slots remaining
-        asm.subl(slotsRemaining, bulkSize);
-        // adjust array pointer
-        asm.addq(arrayPtr, bulkSizeBytes);
+        emitVectorCompare(asm, vectorCompareKind, nVectors, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, false, !findTwoConsecutive);
+        // adjust index
+        asm.addq(index, bulkSize);
         // check if there are enough array slots remaining for the bulk loop
-        asm.cmpl(slotsRemaining, bulkLoopCondition);
-        asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit);
-        // continue loop
-        asm.jmp(bulkVectorLoop);
+        asm.cmpq(index, arrayLength);
+        asm.jccb(AMD64Assembler.ConditionFlag.LessEqual, bulkVectorLoop);
 
-        if (nVectors > 1) {
+        asm.bind(skipBulkVectorLoop);
+        if ((findTwoConsecutive && nVectors == 2) || nVectors == 1) {
+            // do last load from end of array
+            asm.movq(index, arrayLength);
+            // compare
+            emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, true, false);
+        } else {
+            // remove bulk offset
+            asm.subq(index, bulkSize);
             emitAlign(crb, asm);
             // same loop as bulkVectorLoop, with only one vector
             asm.bind(singleVectorLoop);
-            // check if single vector load is in bounds
-            asm.cmpl(slotsRemaining, singleVectorLoopCondition);
-            asm.jcc(AMD64Assembler.ConditionFlag.Below, lessThanVectorSizeRemaining);
+            // add vector size
+            asm.addq(index, vectorSize);
+            // check if vector load is in bounds
+            asm.cmpq(index, arrayLength);
+            // if load would be over bounds, set the load to the end of the array
+            asm.cmovq(AMD64Assembler.ConditionFlag.Greater, index, arrayLength);
             // compare
-            emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoConsecutive ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false);
-            // adjust number of array slots remaining
-            asm.subl(slotsRemaining, arraySlotsPerVector);
-            // adjust array pointer
-            asm.addq(arrayPtr, bytesPerVector);
-            // continue loop
-            asm.jmpb(singleVectorLoop);
-        }
-
-        asm.bind(lessThanVectorSizeRemaining);
-        // check if any array slots remain
-        asm.testl(slotsRemaining, slotsRemaining);
-        asm.jcc(AMD64Assembler.ConditionFlag.Zero, retNotFound);
-
-        // a vector compare will read out of bounds of the input array.
-        // check if the out-of-bounds read would cross a memory page boundary.
-        // load copy of low part of array pointer
-        asm.movl(tmpArrayPtrLow, arrayPtr);
-        // check if pointer + vector size would cross the page boundary
-        asm.andl(tmpArrayPtrLow, (vmPageSize - 1));
-        asm.cmpl(tmpArrayPtrLow, (vmPageSize - (findTwoConsecutive ? bytesPerVector + kind.getByteCount() : bytesPerVector)));
-        // if the page boundary would be crossed, do byte/character-wise comparison instead.
-        asm.jccb(AMD64Assembler.ConditionFlag.Above, lessThanVectorSizeRemainingLoop);
-
-        Label[] overBoundsMatch = {new Label(), new Label()};
-        // otherwise, do a vector compare that reads beyond array bounds
-        emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoConsecutive ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, overBoundsMatch, false);
-        // no match
-        asm.jmp(retNotFound);
-        if (findTwoConsecutive) {
-            Label overBoundsFinish = new Label();
-            asm.bind(overBoundsMatch[1]);
-            // get match offset of second result
-            asm.bsfq(cmpResult[1], cmpResult[1]);
-            asm.addl(cmpResult[1], kind.getByteCount());
-            // replace first result with second and continue
-            asm.movl(cmpResult[0], cmpResult[1]);
-            asm.jmpb(overBoundsFinish);
-
-            asm.bind(overBoundsMatch[0]);
-            emitFindTwoCharPrefixMinResult(asm, kind, cmpResult, overBoundsFinish);
-        } else {
-            asm.bind(overBoundsMatch[0]);
-            // find match offset
-            asm.bsfq(cmpResult[0], cmpResult[0]);
+            emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, true, false);
+            // check if there are enough array slots remaining for the loop
+            asm.cmpq(index, arrayLength);
+            asm.jccb(AMD64Assembler.ConditionFlag.Less, singleVectorLoop);
         }
 
-        // adjust array pointer for match result
-        asm.addq(arrayPtr, cmpResult[0]);
-        if (charMode(kind)) {
-            // convert byte offset to chars
-            asm.shrl(cmpResult[0], 1);
-        }
-        // check if offset of matched value is greater than number of bytes remaining / out of array
-        // bounds
+        asm.movl(index, -1);
+        asm.jmpb(ret);
+
         if (findTwoConsecutive) {
-            asm.decrementl(slotsRemaining);
-        }
-        asm.cmpl(cmpResult[0], slotsRemaining);
-        // match is out of bounds, return no match
-        asm.jcc(AMD64Assembler.ConditionFlag.GreaterEqual, retNotFound);
-        // adjust number of array slots remaining
-        if (findTwoConsecutive) {
-            asm.incrementl(slotsRemaining, 1);
+            Label vectorFound2Done = new Label();
+
+            // vectorFound[0] and vectorFound[2] behave like the single-char case
+            asm.bind(vectorFound[2]);
+            // add static offset
+            asm.subq(index, getResultIndexDelta(2));
+            asm.jmpb(vectorFound2Done);
+
+            asm.bind(vectorFound[0]);
+            // add static offset
+            asm.subq(index, getResultIndexDelta(0));
+            asm.bind(vectorFound2Done);
+            // find offset
+            asm.bsfq(cmpResult[0], cmpResult[0]);
+            if (charMode(valueKind)) {
+                // convert byte offset to chars
+                asm.shrl(cmpResult[0], 1);
+            }
+            // add offset to index
+            asm.addq(index, cmpResult[0]);
+            asm.jmpb(ret);
+
+            Label minResult = new Label();
+            Label minResultDone = new Label();
+
+            // in vectorFound[1] and vectorFound[3], we have to check the results 0 and 2 as well
+            if (nVectors > 2) {
+                asm.bind(vectorFound[3]);
+                // add offset
+                asm.subq(index, getResultIndexDelta(3));
+                asm.jmpb(minResult);
+            }
+
+            asm.bind(vectorFound[1]);
+            // add offset
+            asm.subq(index, getResultIndexDelta(1));
+
+            asm.bind(minResult);
+            // find offset 0
+            asm.bsfq(cmpResult[1], cmpResult[1]);
+            // check if second result is also a match
+            asm.testq(cmpResult[0], cmpResult[0]);
+            asm.jccb(AMD64Assembler.ConditionFlag.Zero, minResultDone);
+            // find offset 1
+            asm.bsfq(cmpResult[0], cmpResult[0]);
+            asm.addq(cmpResult[0], valueKind.getByteCount());
+            // if first result is greater than second, replace it with the second result
+            asm.cmpq(cmpResult[1], cmpResult[0]);
+            asm.cmovq(AMD64Assembler.ConditionFlag.Greater, cmpResult[1], cmpResult[0]);
+            asm.bind(minResultDone);
+            if (charMode(valueKind)) {
+                // convert byte offset to chars
+                asm.shrl(cmpResult[1], 1);
+            }
+            // add offset to index
+            asm.addq(index, cmpResult[1]);
+        } else {
+            Label end = new Label();
+            for (int i = 0; i < nVectors; i++) {
+                asm.bind(vectorFound[i]);
+                // add static offset
+                asm.subq(index, getResultIndexDelta(i));
+                if (i < nVectors - 1) {
+                    asm.jmpb(end);
+                }
+            }
+            asm.bind(end);
+            // find offset
+            asm.bsfq(cmpResult[0], cmpResult[0]);
+            if (charMode(valueKind)) {
+                // convert byte offset to chars
+                asm.shrl(cmpResult[0], 1);
+            }
+            // add offset to index
+            asm.addq(index, cmpResult[0]);
         }
-        asm.subl(slotsRemaining, cmpResult[0]);
-        // match is in bounds, return offset
-        asm.jmp(retFound);
+        asm.bind(ret);
+    }
 
-        // compare remaining slots in the array one-by-one
-        asm.bind(lessThanVectorSizeRemainingLoop);
-        // check if enough array slots remain
-        asm.cmpl(slotsRemaining, findTwoConsecutive ? 1 : 0);
-        asm.jcc(AMD64Assembler.ConditionFlag.LessEqual, retNotFound);
-        // load char / byte
-        if (byteMode(kind)) {
-            if (findTwoConsecutive) {
-                asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr));
-            } else {
-                asm.movzbl(cmpResult[0], new AMD64Address(arrayPtr));
-            }
-        } else {
-            if (findTwoConsecutive) {
-                asm.movl(cmpResult[0], new AMD64Address(arrayPtr));
-            } else {
-                asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr));
+    private boolean searchValuesOnStack(Value[] searchValue) {
+        for (int i = 0; i < nValues; i++) {
+            if (isStackSlot(searchValue[i])) {
+                return true;
             }
         }
-        // check for match
-        for (int i = 0; i < nValues; i++) {
-            emitCompareInst(asm, getComparisonKind(), cmpResult[0], searchValue[i]);
-            asm.jcc(AMD64Assembler.ConditionFlag.Equal, retFound);
-        }
-        // adjust number of array slots remaining
-        asm.decrementl(slotsRemaining);
-        // adjust array pointer
-        asm.addq(arrayPtr, kind.getByteCount());
-        // continue loop
-        asm.jmpb(lessThanVectorSizeRemainingLoop);
+        return false;
+    }
 
-        for (int i = 1; i < nVectors; i += (findTwoConsecutive ? 2 : 1)) {
-            emitVectorFoundWithOffset(asm, kind, vectorOffsets[i], arrayPtr, cmpResult[i], slotsRemaining, vectorFound[i], retFound);
-        }
+    private int getResultIndexDelta(int i) {
+        return (((findTwoConsecutive ? i / 2 : i) + 1) * (getVectorSize().getBytes() / valueKind.getByteCount())) + (findTwoConsecutive ? (i & 1) : 0);
+    }
 
-        if (findTwoConsecutive) {
-            asm.bind(vectorFound[2]);
-            asm.addq(arrayPtr, vectorOffsets[2]);
-            // adjust number of array slots remaining
-            asm.subl(slotsRemaining, charMode(kind) ? vectorOffsets[2] / 2 : vectorOffsets[2]);
-            asm.movl(cmpResult[0], cmpResult[2]);
-            asm.movl(cmpResult[1], cmpResult[3]);
-            asm.bind(vectorFound[0]);
-            emitFindTwoCharPrefixMinResult(asm, kind, cmpResult, new Label());
+    private int getVectorOffset(int i) {
+        return arrayBaseOffset - getResultIndexDelta(i) * valueKind.getByteCount();
+    }
+
+    private void broadcastSearchValue(CompilationResultBuilder crb, AMD64MacroAssembler asm, Register dst, Value srcVal, Register tmpReg, Register tmpVector) {
+        Register src = asRegOrTmpReg(crb, asm, srcVal, tmpReg);
+        if (asm.supports(CPUFeature.AVX)) {
+            VexMoveOp.VMOVD.emit(asm, AVXKind.AVXSize.DWORD, dst, src);
         } else {
-            asm.bind(vectorFound[0]);
-            // find index of first set bit in bit mask
-            asm.bsfq(cmpResult[0], cmpResult[0]);
+            asm.movdl(dst, src);
         }
-        // add offset to array pointer
-        asm.addq(arrayPtr, cmpResult[0]);
-        if (charMode(kind)) {
-            // convert byte offset to chars
-            asm.shrl(cmpResult[0], 1);
-        }
-        // adjust number of array slots remaining
-        asm.subl(slotsRemaining, cmpResult[0]);
-        asm.jmpb(retFound);
+        emitBroadcast(asm, getComparisonKind(), dst, tmpVector, getVectorSize());
     }
 
-    private static void emitFindTwoCharPrefixMinResult(AMD64MacroAssembler asm, JavaKind kind, Register[] cmpResult, Label done) {
-        // find match offset
-        asm.bsfq(cmpResult[0], cmpResult[0]);
-        // check if second result is also a match
-        asm.testl(cmpResult[1], cmpResult[1]);
-        asm.jcc(AMD64Assembler.ConditionFlag.Zero, done);
-        // get match offset of second result
-        asm.bsfq(cmpResult[1], cmpResult[1]);
-        asm.addl(cmpResult[1], kind.getByteCount());
-        // check if first result is less than second
-        asm.cmpl(cmpResult[0], cmpResult[1]);
-        asm.jcc(AMD64Assembler.ConditionFlag.LessEqual, done);
-        // first result is greater than second, replace it with the second result
-        asm.movl(cmpResult[0], cmpResult[1]);
-        asm.bind(done);
+    private static boolean isConstant(Value val) {
+        assert !(val instanceof ConstantValue) || ((ConstantValue) val).isJavaConstant();
+        return val instanceof ConstantValue;
+    }
+
+    private static JavaConstant asConstant(Value val) {
+        return ((ConstantValue) val).getJavaConstant();
+    }
+
+    private static Register asRegOrTmpReg(CompilationResultBuilder crb, AMD64MacroAssembler asm, Value val, Register tmpReg) {
+        if (isRegister(val)) {
+            return asRegister(val);
+        } else if (isStackSlot(val)) {
+            asm.movl(tmpReg, (AMD64Address) crb.asAddress(val));
+            return tmpReg;
+        } else {
+            assert isConstant(val);
+            asm.movl(tmpReg, asConstant(val).asInt());
+            return tmpReg;
+        }
     }
 
     private static void emitAlign(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
@@ -493,92 +505,64 @@
         }
     }
 
-    /**
-     * Convert a byte offset stored in {@code bytes} to an array index offset.
-     */
-    private static void emitBytesToArraySlots(AMD64MacroAssembler asm, JavaKind kind, Register bytes) {
-        if (charMode(kind)) {
-            asm.shrl(bytes, 1);
-        } else {
-            assert byteMode(kind);
-        }
-    }
-
-    private static void emitVectorCompare(AMD64MacroAssembler asm,
+    private void emitVectorCompare(AMD64MacroAssembler asm,
                     JavaKind kind,
-                    AVXKind.AVXSize vectorSize,
-                    int nValues,
                     int nVectors,
-                    int[] vectorOffsets,
                     Register arrayPtr,
+                    Register index,
                     Register[] vecCmp,
                     Register[] vecArray,
                     Register[] cmpResult,
                     Label[] vectorFound,
+                    boolean shortJmp,
                     boolean alignedLoad) {
         // load array contents into vectors
-        for (int i = 0; i < nValues; i++) {
-            for (int j = 0; j < nVectors; j++) {
-                emitArrayLoad(asm, vectorSize, vecArray[(i * nVectors) + j], arrayPtr, vectorOffsets[j], alignedLoad);
+        for (int i = 0; i < nVectors; i++) {
+            int base = i * nValues;
+            for (int j = 0; j < nValues; j++) {
+                emitArrayLoad(asm, getVectorSize(), vecArray[base + j], arrayPtr, index, getVectorOffset(nVectors - (i + 1)), alignedLoad);
             }
         }
         // compare all loaded bytes to the search value.
         // matching bytes are set to 0xff, non-matching bytes are set to 0x00.
-        for (int i = 0; i < nValues; i++) {
-            for (int j = 0; j < nVectors; j++) {
-                emitVectorCompareInst(asm, kind, vectorSize, vecArray[(i * nVectors) + j], vecCmp[i]);
+        if (!findTwoConsecutive) {
+            for (int i = 0; i < nVectors; i++) {
+                int base = i * nValues;
+                for (int j = 0; j < nValues; j++) {
+                    emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[base + j], vecCmp[j]);
+                    if ((j & 1) == 1) {
+                        emitPOR(asm, getVectorSize(), vecArray[base + j - 1], vecArray[base + j]);
+                    }
+                }
+                if (nValues > 2) {
+                    emitPOR(asm, getVectorSize(), vecArray[base], vecArray[base + 2]);
+                }
+                emitMOVMSK(asm, getVectorSize(), cmpResult[0], vecArray[base]);
+                emitJnz(asm, cmpResult[0], vectorFound[nVectors - (i + 1)], shortJmp);
             }
-        }
-        // create 32-bit-masks from the most significant bit of every byte in the comparison
-        // results.
-        for (int i = 0; i < nValues * nVectors; i++) {
-            emitMOVMSK(asm, vectorSize, cmpResult[i], vecArray[i]);
-        }
-        // join results of comparisons against multiple values
-        for (int stride = 1; stride < nValues; stride *= 2) {
-            for (int i = 0; i < nVectors; i++) {
-                for (int j = 0; j + stride < nValues; j += stride * 2) {
-                    asm.orl(cmpResult[i + (j * nVectors)], cmpResult[i + ((j + stride) * nVectors)]);
-                }
+        } else {
+            for (int i = 0; i < nVectors; i += 2) {
+                emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[i], vecCmp[0]);
+                emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[i + 1], vecCmp[0]);
+                emitMOVMSK(asm, getVectorSize(), cmpResult[1], vecArray[i]);
+                emitMOVMSK(asm, getVectorSize(), cmpResult[0], vecArray[i + 1]);
+                emitJnz(asm, cmpResult[1], vectorFound[nVectors - (i + 1)], shortJmp);
+                emitJnz(asm, cmpResult[0], vectorFound[nVectors - (i + 2)], shortJmp);
             }
         }
-        // check if a match was found
-        for (int i = 0; i < nVectors; i++) {
-            asm.testl(cmpResult[i], cmpResult[i]);
-            asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound[i]);
-        }
     }
 
-    private static void emitVectorFoundWithOffset(AMD64MacroAssembler asm,
-                    JavaKind kind,
-                    int resultOffset,
-                    Register result,
-                    Register cmpResult,
-                    Register slotsRemaining,
-                    Label entry,
-                    Label ret) {
-        asm.bind(entry);
-        if (resultOffset > 0) {
-            // adjust array pointer
-            asm.addq(result, resultOffset);
-            // adjust number of array slots remaining
-            asm.subl(slotsRemaining, charMode(kind) ? resultOffset / 2 : resultOffset);
+    private static void emitJnz(AMD64MacroAssembler asm, Register cond, Label tgt, boolean shortJmp) {
+        asm.testl(cond, cond);
+        if (shortJmp) {
+            asm.jccb(AMD64Assembler.ConditionFlag.NotZero, tgt);
+        } else {
+            asm.jcc(AMD64Assembler.ConditionFlag.NotZero, tgt);
         }
-        // find index of first set bit in bit mask
-        asm.bsfq(cmpResult, cmpResult);
-        // add offset to array pointer
-        asm.addq(result, cmpResult);
-        if (charMode(kind)) {
-            // convert byte offset to chars
-            asm.shrl(cmpResult, 1);
-        }
-        // adjust number of array slots remaining
-        asm.subl(slotsRemaining, cmpResult);
-        asm.jmpb(ret);
     }
 
-    private static void emitArrayLoad(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register vecDst, Register arrayPtr, int offset, boolean alignedLoad) {
-        AMD64Address src = new AMD64Address(arrayPtr, offset);
+    private void emitArrayLoad(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register vecDst, Register arrayPtr, Register index, int offset, boolean alignedLoad) {
+        AMD64Address src = new AMD64Address(arrayPtr, index, arrayIndexScale, offset);
         if (asm.supports(CPUFeature.AVX)) {
             VexMoveOp loadOp = alignedLoad ? VexMoveOp.VMOVDQA : VexMoveOp.VMOVDQU;
             loadOp.emit(asm, vectorSize, vecDst, src);
@@ -621,6 +605,15 @@
         }
     }
 
+    private static void emitPOR(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register dst, Register vecSrc) {
+        if (asm.supports(CPUFeature.AVX)) {
+            VexRVMOp.VPOR.emit(asm, vectorSize, dst, dst, vecSrc);
+        } else {
+            // SSE
+            asm.por(dst, vecSrc);
+        }
+    }
+
     private static void emitMOVMSK(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register dst, Register vecSrc) {
         if (asm.supports(CPUFeature.AVX)) {
             VexRMOp.VPMOVMSKB.emit(asm, vectorSize, dst, vecSrc);
@@ -630,20 +623,17 @@
         }
     }
 
-    private static void emitCompareInst(AMD64MacroAssembler asm, JavaKind kind, Register dst, Register src) {
+    private static OperandSize getOpSize(JavaKind kind) {
         switch (kind) {
             case Byte:
-                asm.cmpb(dst, src);
-                break;
+                return OperandSize.BYTE;
             case Short:
             case Char:
-                asm.cmpw(dst, src);
-                break;
+                return OperandSize.WORD;
             case Int:
-                asm.cmpl(dst, src);
-                break;
+                return OperandSize.DWORD;
             default:
-                asm.cmpq(dst, src);
+                return OperandSize.QWORD;
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/BailoutAndRestartBackendException.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/BailoutAndRestartBackendException.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,24 +25,12 @@
 package org.graalvm.compiler.lir;
 
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionKey;
-import org.graalvm.compiler.options.OptionType;
 
 /**
  * Restarts the {@link LIR low-level} compilation with a modified configuration.
- * {@link BailoutAndRestartBackendException.Options#LIRUnlockBackendRestart LIRUnlockBackendRestart}
- * needs to be enabled. Use only for debugging purposes only.
  */
 public abstract class BailoutAndRestartBackendException extends PermanentBailoutException {
 
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Unlock backend restart feature.", type = OptionType.Debug)
-        public static final OptionKey<Boolean> LIRUnlockBackendRestart = new OptionKey<>(false);
-        // @formatter:on
-    }
-
     private static final long serialVersionUID = 792969002851591180L;
 
     public BailoutAndRestartBackendException(String msg) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIR.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIR.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,8 +34,8 @@
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
+import org.graalvm.compiler.lir.StandardOp.LabelHoldingOp;
 import org.graalvm.compiler.lir.StandardOp.LabelOp;
-import org.graalvm.compiler.lir.StandardOp.LabelHoldingOp;
 import org.graalvm.compiler.lir.gen.LIRGenerator;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -72,7 +72,11 @@
     /**
      * Creates a new LIR instance for the specified compilation.
      */
-    public LIR(AbstractControlFlowGraph<?> cfg, AbstractBlockBase<?>[] linearScanOrder, AbstractBlockBase<?>[] codeEmittingOrder, OptionValues options, DebugContext debug) {
+    public LIR(AbstractControlFlowGraph<?> cfg,
+                    AbstractBlockBase<?>[] linearScanOrder,
+                    AbstractBlockBase<?>[] codeEmittingOrder,
+                    OptionValues options,
+                    DebugContext debug) {
         this.cfg = cfg;
         this.codeEmittingOrder = codeEmittingOrder;
         this.linearScanOrder = linearScanOrder;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarkerPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/dfa/LocationMarkerPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -37,14 +37,15 @@
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.phases.AllocationPhase;
 
+import jdk.vm.ci.code.ReferenceMap;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterAttributes;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
 
 /**
- * Mark all live references for a frame state. The frame state use this information to build the OOP
- * maps.
+ * Mark all live references for a frame state. The frame state uses this information to build the
+ * {@link ReferenceMap}s.
  */
 public final class LocationMarkerPhase extends AllocationPhase {
 
@@ -93,7 +94,6 @@
             }
 
             ReferenceMapBuilder refMap = frameMap.newReferenceMapBuilder();
-            frameMap.addLiveValues(refMap);
             values.addLiveValues(refMap);
 
             info.debugInfo().setReferenceMap(refMap.finish(info));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMap.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMap.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,13 +24,9 @@
 
 package org.graalvm.compiler.lir.framemap;
 
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-
+import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.core.common.LIRKind;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.CallingConvention;
@@ -38,14 +34,13 @@
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.meta.ValueKind;
 
 /**
  * This class is used to build the stack frame layout for a compiled method. A {@link StackSlot} is
  * used to index slots of the frame relative to the stack pointer. The frame size is only fixed
  * after register allocation when all spill slots have been allocated. Both the outgoing argument
- * area and the spill are can grow until then. Therefore, outgoing arguments are indexed from the
+ * area and the spill area can grow until then. Therefore, outgoing arguments are indexed from the
  * stack pointer, while spill slots are indexed from the beginning of the frame (and the total frame
  * size has to be added to get the actual offset from the stack pointer).
  */
@@ -91,11 +86,6 @@
     protected boolean hasOutgoingStackArguments;
 
     /**
-     * The list of stack slots allocated in this frame that are present in every reference map.
-     */
-    private final List<StackSlot> objectStackSlots;
-
-    /**
      * Records whether an offset to an incoming stack argument was ever returned by
      * {@link #offsetForStackSlot(StackSlot)}.
      */
@@ -110,7 +100,6 @@
         this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
         this.frameSize = -1;
         this.outgoingSize = codeCache.getMinimumOutgoingSize();
-        this.objectStackSlots = new ArrayList<>();
         this.referenceMapFactory = referenceMapFactory;
     }
 
@@ -122,12 +111,6 @@
         return target;
     }
 
-    public void addLiveValues(ReferenceMapBuilder refMap) {
-        for (Value value : objectStackSlots) {
-            refMap.addLiveValue(value);
-        }
-    }
-
     protected int returnAddressSize() {
         return getTarget().arch.getReturnAddressSize();
     }
@@ -235,19 +218,6 @@
     }
 
     /**
-     * Reserves a new spill slot in the frame of the method being compiled. The returned slot is
-     * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte
-     * boundary.
-     *
-     * @param kind The kind of the spill slot to be reserved.
-     * @param additionalOffset
-     * @return A spill slot denoting the reserved memory area.
-     */
-    protected StackSlot allocateNewSpillSlot(ValueKind<?> kind, int additionalOffset) {
-        return StackSlot.get(kind, -spillSize + additionalOffset, true);
-    }
-
-    /**
      * Returns the spill slot size for the given {@link ValueKind}. The default value is the size in
      * bytes for the target architecture.
      *
@@ -270,7 +240,11 @@
         assert frameSize == -1 : "frame size must not yet be fixed";
         int size = spillSlotSize(kind);
         spillSize = NumUtil.roundUp(spillSize + size, size);
-        return allocateNewSpillSlot(kind, 0);
+        return newStackSlot(kind);
+    }
+
+    private StackSlot newStackSlot(ValueKind<?> kind) {
+        return StackSlot.get(kind, -spillSize, true);
     }
 
     /**
@@ -288,46 +262,15 @@
      * requested number of slots is 0, this method returns {@code null}.
      *
      * @param slots the number of slots to reserve
-     * @param objects specifies the indexes of the object pointer slots. The caller is responsible
-     *            for guaranteeing that each such object pointer slot is initialized before any
-     *            instruction that uses a reference map. Without this guarantee, the garbage
-     *            collector could see garbage object values.
      * @return the first reserved stack slot (i.e., at the lowest address)
      */
-    public StackSlot allocateStackSlots(int slots, BitSet objects) {
+    public StackSlot allocateStackSlots(int slots) {
         assert frameSize == -1 : "frame size must not yet be fixed";
         if (slots == 0) {
             return null;
         }
-        spillSize += spillSlotRangeSize(slots);
-
-        if (!objects.isEmpty()) {
-            assert objects.length() <= slots;
-            StackSlot result = null;
-            for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
-                StackSlot objectSlot = null;
-                if (objects.get(slotIndex)) {
-                    objectSlot = allocateNewSpillSlot(LIRKind.reference(getTarget().arch.getWordKind()), slotIndex * getTarget().wordSize);
-                    addObjectStackSlot(objectSlot);
-                }
-                if (slotIndex == 0) {
-                    if (objectSlot != null) {
-                        result = objectSlot;
-                    } else {
-                        result = allocateNewSpillSlot(LIRKind.value(getTarget().arch.getWordKind()), 0);
-                    }
-                }
-            }
-            assert result != null;
-            return result;
-
-        } else {
-            return allocateNewSpillSlot(LIRKind.value(getTarget().arch.getWordKind()), 0);
-        }
-    }
-
-    protected void addObjectStackSlot(StackSlot objectSlot) {
-        objectStackSlots.add(objectSlot);
+        spillSize = NumUtil.roundUp(spillSize + spillSlotRangeSize(slots), getTarget().wordSize);
+        return newStackSlot(LIRKind.value(getTarget().arch.getWordKind()));
     }
 
     public ReferenceMapBuilder newReferenceMapBuilder() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,9 +24,6 @@
 
 package org.graalvm.compiler.lir.framemap;
 
-import java.util.BitSet;
-import java.util.List;
-
 import org.graalvm.compiler.lir.VirtualStackSlot;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 
@@ -56,15 +53,9 @@
      * requested number of slots is 0, this method returns {@code null}.
      *
      * @param slots the number of slots to reserve
-     * @param objects specifies the indexes of the object pointer slots. The caller is responsible
-     *            for guaranteeing that each such object pointer slot is initialized before any
-     *            instruction that uses a reference map. Without this guarantee, the garbage
-     *            collector could see garbage object values.
-     * @param outObjectStackSlots if non-null, the object pointer slots allocated are added to this
-     *            list
      * @return the first reserved stack slot (i.e., at the lowest address)
      */
-    public abstract VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots);
+    public abstract VirtualStackSlot allocateStackSlots(int slots);
 
     public abstract RegisterConfig getRegisterConfig();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/FrameMapBuilderImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,14 +27,12 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.EnumSet;
 import java.util.List;
 
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.InstructionValueConsumer;
 import org.graalvm.compiler.lir.LIR;
 import org.graalvm.compiler.lir.LIRInstruction;
@@ -46,7 +44,6 @@
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.RegisterConfig;
-import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.meta.ValueKind;
 
@@ -80,14 +77,11 @@
     }
 
     @Override
-    public VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots) {
+    public VirtualStackSlot allocateStackSlots(int slots) {
         if (slots == 0) {
             return null;
         }
-        if (outObjectStackSlots != null) {
-            throw GraalError.unimplemented();
-        }
-        VirtualStackSlotRange slot = new VirtualStackSlotRange(numStackSlots++, slots, objects, LIRKind.fromJavaKind(frameMap.getTarget().arch, JavaKind.Object));
+        VirtualStackSlotRange slot = new VirtualStackSlotRange(numStackSlots++, slots, LIRKind.value(frameMap.getTarget().arch.getWordKind()));
         stackSlots.add(slot);
         return slot;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/VirtualStackSlotRange.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/framemap/VirtualStackSlotRange.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,8 +24,6 @@
 
 package org.graalvm.compiler.lir.framemap;
 
-import java.util.BitSet;
-
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.lir.VirtualStackSlot;
 
@@ -37,21 +35,14 @@
  */
 public class VirtualStackSlotRange extends VirtualStackSlot {
 
-    private final BitSet objects;
     private final int slots;
 
-    public VirtualStackSlotRange(int id, int slots, BitSet objects, LIRKind kind) {
+    public VirtualStackSlotRange(int id, int slots, LIRKind kind) {
         super(id, kind);
         this.slots = slots;
-        this.objects = (BitSet) objects.clone();
     }
 
     public int getSlots() {
         return slots;
     }
-
-    public BitSet getObjects() {
-        return (BitSet) objects.clone();
-    }
-
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,9 +24,6 @@
 
 package org.graalvm.compiler.lir.gen;
 
-import java.util.BitSet;
-import java.util.List;
-
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.calc.Condition;
@@ -274,7 +271,7 @@
     }
 
     @SuppressWarnings("unused")
-    default Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value sourcePointer, Value sourceCount, Value... searchValues) {
+    default Variable emitArrayIndexOf(JavaKind arrayKind, JavaKind valueKind, boolean findTwoConsecutive, Value sourcePointer, Value sourceCount, Value fromIndex, Value... searchValues) {
         throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture");
     }
 
@@ -324,8 +321,8 @@
      */
     void emitSpeculationFence();
 
-    default VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots) {
-        return getResult().getFrameMapBuilder().allocateStackSlots(slots, objects, outObjectStackSlots);
+    default VirtualStackSlot allocateStackSlots(int slots) {
+        return getResult().getFrameMapBuilder().allocateStackSlots(slots);
     }
 
     default Value emitReadCallerStackPointer(Stamp wordStamp) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,11 +33,12 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Deque;
-import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.PriorityQueue;
+import java.util.function.Predicate;
 
 import jdk.internal.vm.compiler.collections.EconomicSet;
+import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
@@ -49,6 +50,7 @@
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
 import org.graalvm.compiler.lir.ValueProcedure;
 import org.graalvm.compiler.lir.VirtualStackSlot;
+import org.graalvm.compiler.lir.framemap.FrameMap;
 import org.graalvm.compiler.lir.framemap.FrameMapBuilderTool;
 import org.graalvm.compiler.lir.framemap.SimpleVirtualStackSlot;
 import org.graalvm.compiler.lir.framemap.VirtualStackSlotRange;
@@ -58,6 +60,7 @@
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionType;
 
+import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
@@ -156,7 +159,15 @@
             }
             // step 4: allocate stack slots
             try (DebugCloseable t = AllocateSlotsTimer.start(debug)) {
-                allocateStackSlots();
+                /*
+                 * Allocate primitive spill slots before reference spill slots. This ensures a
+                 * ReferenceMap will be as compact as possible and only exceed the encoding limit of
+                 * a stack offset if there are really too many objects live on the stack at an
+                 * instruction with a ReferenceMap (as opposed to the method simply having a very
+                 * large frame).
+                 */
+                allocateStackSlots(IS_PRIMITIVE_INTERVAL);
+                allocateStackSlots(IS_REFERENCE_INTERVAL);
             }
             if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) {
                 dumpIntervals("After stack slot allocation");
@@ -226,29 +237,44 @@
         // ====================
 
         @SuppressWarnings("try")
-        private void allocateStackSlots() {
-            // create unhandled lists
+        private void allocateStackSlots(Predicate<StackInterval> predicate) {
             for (StackInterval interval : stackSlotMap) {
-                if (interval != null) {
+                if (interval != null && (predicate == null || predicate.test(interval))) {
                     unhandled.add(interval);
                 }
             }
-
             for (StackInterval current = activateNext(); current != null; current = activateNext()) {
                 try (Indent indent = debug.logAndIndent("allocate %s", current)) {
                     allocateSlot(current);
                 }
             }
 
+            // Cannot re-use free slots between rounds of slot allocation
+            freeSlots = null;
+            active.clear();
         }
 
+        private static final Predicate<StackInterval> IS_REFERENCE_INTERVAL = new Predicate<StackInterval>() {
+            @Override
+            public boolean test(StackInterval interval) {
+                return !((LIRKind) interval.kind()).isValue();
+            }
+        };
+
+        private static final Predicate<StackInterval> IS_PRIMITIVE_INTERVAL = new Predicate<StackInterval>() {
+            @Override
+            public boolean test(StackInterval interval) {
+                return ((LIRKind) interval.kind()).isValue();
+            }
+        };
+
         private void allocateSlot(StackInterval current) {
             VirtualStackSlot virtualSlot = current.getOperand();
             final StackSlot location;
             if (virtualSlot instanceof VirtualStackSlotRange) {
                 // No reuse of ranges (yet).
                 VirtualStackSlotRange slotRange = (VirtualStackSlotRange) virtualSlot;
-                location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots(), slotRange.getObjects());
+                location = frameMapBuilder.getFrameMap().allocateStackSlots(slotRange.getSlots());
                 StackSlotAllocatorUtil.virtualFramesize.add(debug, frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots()));
                 StackSlotAllocatorUtil.allocatedSlots.increment(debug);
             } else {
@@ -274,59 +300,44 @@
             current.setLocation(location);
         }
 
-        private enum SlotSize {
-            Size1,
-            Size2,
-            Size4,
-            Size8,
-            Illegal;
-        }
-
-        private SlotSize forKind(ValueKind<?> kind) {
-            switch (frameMapBuilder.getFrameMap().spillSlotSize(kind)) {
-                case 1:
-                    return SlotSize.Size1;
-                case 2:
-                    return SlotSize.Size2;
-                case 4:
-                    return SlotSize.Size4;
-                case 8:
-                    return SlotSize.Size8;
-                default:
-                    return SlotSize.Illegal;
-            }
-        }
-
-        private EnumMap<SlotSize, Deque<StackSlot>> freeSlots;
+        /**
+         * Map from log2 of {@link FrameMap#spillSlotSize(ValueKind) a spill slot size} to a list of
+         * free stack slots.
+         */
+        private ArrayList<Deque<StackSlot>> freeSlots;
 
         /**
-         * @return The list of free stack slots for {@code size} or {@code null} if there is none.
+         * @return The list of free stack slots for {@code index} or {@code null} if there is none.
          */
-        private Deque<StackSlot> getOrNullFreeSlots(SlotSize size) {
+        private Deque<StackSlot> getNullOrFreeSlots(int index) {
             if (freeSlots == null) {
                 return null;
             }
-            return freeSlots.get(size);
+            if (index < freeSlots.size()) {
+                return freeSlots.get(index);
+            }
+            return null;
         }
 
         /**
-         * @return the list of free stack slots for {@code size}. If there is none a list is
+         * @return the list of free stack slots for {@code index}. If there is none a list is
          *         created.
          */
-        private Deque<StackSlot> getOrInitFreeSlots(SlotSize size) {
-            assert size != SlotSize.Illegal;
-            Deque<StackSlot> freeList;
-            if (freeSlots != null) {
-                freeList = freeSlots.get(size);
-            } else {
-                freeSlots = new EnumMap<>(SlotSize.class);
-                freeList = null;
+        private Deque<StackSlot> getOrInitFreeSlots(int index) {
+            Deque<StackSlot> freeList = null;
+            if (freeSlots == null) {
+                freeSlots = new ArrayList<>(6);
+            } else if (index < freeSlots.size()) {
+                freeList = freeSlots.get(index);
             }
             if (freeList == null) {
+                int requiredSize = index + 1;
+                for (int i = freeSlots.size(); i < requiredSize; i++) {
+                    freeSlots.add(null);
+                }
                 freeList = new ArrayDeque<>();
-                freeSlots.put(size, freeList);
+                freeSlots.set(index, freeList);
             }
-            assert freeList != null;
             return freeList;
         }
 
@@ -335,11 +346,8 @@
          */
         private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) {
             assert slot != null;
-            SlotSize size = forKind(slot.getValueKind());
-            if (size == SlotSize.Illegal) {
-                return null;
-            }
-            Deque<StackSlot> freeList = getOrNullFreeSlots(size);
+            int size = log2SpillSlotSize(slot.getValueKind());
+            Deque<StackSlot> freeList = getNullOrFreeSlots(size);
             if (freeList == null) {
                 return null;
             }
@@ -350,13 +358,16 @@
          * Adds a stack slot to the list of free slots.
          */
         private void freeSlot(StackSlot slot) {
-            SlotSize size = forKind(slot.getValueKind());
-            if (size == SlotSize.Illegal) {
-                return;
-            }
+            int size = log2SpillSlotSize(slot.getValueKind());
             getOrInitFreeSlots(size).addLast(slot);
         }
 
+        private int log2SpillSlotSize(ValueKind<?> kind) {
+            int size = frameMapBuilder.getFrameMap().spillSlotSize(kind);
+            assert CodeUtil.isPowerOf2(size);
+            return CodeUtil.log2(size);
+        }
+
         /**
          * Gets the next unhandled interval and finishes handled intervals.
          */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/SimpleStackSlotAllocator.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/SimpleStackSlotAllocator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -113,6 +113,6 @@
     }
 
     protected StackSlot mapVirtualStackSlotRange(FrameMapBuilderTool builder, VirtualStackSlotRange virtualStackSlot) {
-        return builder.getFrameMap().allocateStackSlots(virtualStackSlot.getSlots(), virtualStackSlot.getObjects());
+        return builder.getFrameMap().allocateStackSlots(virtualStackSlot.getSlots());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ContextlessLoopPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ContextlessLoopPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,7 +26,7 @@
 
 import org.graalvm.compiler.loop.LoopPolicies;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 
 public abstract class ContextlessLoopPhase<P extends LoopPolicies> extends LoopPhase<P> {
 
@@ -45,7 +45,7 @@
     protected abstract void run(StructuredGraph graph);
 
     @Override
-    protected final void run(StructuredGraph graph, PhaseContext context) {
+    protected final void run(StructuredGraph graph, CoreProviders context) {
         run(graph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -59,12 +59,12 @@
 import org.graalvm.compiler.nodes.ValuePhiNode;
 import org.graalvm.compiler.nodes.calc.CompareNode;
 import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.LazyValue;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -81,10 +81,10 @@
  * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
  *
  */
-public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
+public class ConvertDeoptimizeToGuardPhase extends BasePhase<CoreProviders> {
     @Override
     @SuppressWarnings("try")
-    protected void run(final StructuredGraph graph, PhaseContext context) {
+    protected void run(final StructuredGraph graph, CoreProviders context) {
         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
         assert !graph.getGuardsStage().areFrameStatesAtDeopts() : graph.getGuardsStage();
         LazyValue<LoopsData> lazyLoops = new LazyValue<>(() -> new LoopsData(graph));
@@ -110,7 +110,7 @@
         new DeadCodeEliminationPhase(Optional).apply(graph);
     }
 
-    private static void trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context, LazyValue<LoopsData> lazyLoops) {
+    private static void trySplitFixedGuard(FixedGuardNode fixedGuard, CoreProviders context, LazyValue<LoopsData> lazyLoops) {
         LogicNode condition = fixedGuard.condition();
         if (condition instanceof CompareNode) {
             CompareNode compare = (CompareNode) condition;
@@ -126,7 +126,7 @@
         }
     }
 
-    private static void processFixedGuardAndPhis(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
+    private static void processFixedGuardAndPhis(FixedGuardNode fixedGuard, CoreProviders context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
                     LazyValue<LoopsData> lazyLoops) {
         AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard);
         if (pred instanceof AbstractMergeNode) {
@@ -143,7 +143,7 @@
     }
 
     @SuppressWarnings("try")
-    private static void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
+    private static void processFixedGuardAndMerge(FixedGuardNode fixedGuard, CoreProviders context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
                     AbstractMergeNode merge, LazyValue<LoopsData> lazyLoops) {
         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
         for (AbstractEndNode mergePredecessor : mergePredecessors) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,14 +24,15 @@
 
 package org.graalvm.compiler.loop.phases;
 
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopPolicies;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
 
@@ -44,26 +45,28 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        DebugContext debug = graph.getDebug();
-        if (graph.hasLoops()) {
-            boolean peeled;
-            do {
-                peeled = false;
-                final LoopsData dataCounted = new LoopsData(graph);
-                dataCounted.detectedCountedLoops();
-                for (LoopEx loop : dataCounted.countedLoops()) {
-                    if (getPolicies().shouldFullUnroll(loop)) {
-                        debug.log("FullUnroll %s", loop);
-                        LoopTransformations.fullUnroll(loop, context, canonicalizer);
-                        FULLY_UNROLLED_LOOPS.increment(debug);
-                        debug.dump(DebugContext.DETAILED_LEVEL, graph, "FullUnroll %s", loop);
-                        peeled = true;
-                        break;
+    protected void run(StructuredGraph graph, CoreProviders context) {
+        if (GraalOptions.FullUnroll.getValue(graph.getOptions())) {
+            DebugContext debug = graph.getDebug();
+            if (graph.hasLoops()) {
+                boolean peeled;
+                do {
+                    peeled = false;
+                    final LoopsData dataCounted = new LoopsData(graph);
+                    dataCounted.detectedCountedLoops();
+                    for (LoopEx loop : dataCounted.countedLoops()) {
+                        if (getPolicies().shouldFullUnroll(loop)) {
+                            debug.log("FullUnroll %s", loop);
+                            LoopTransformations.fullUnroll(loop, context, canonicalizer);
+                            FULLY_UNROLLED_LOOPS.increment(debug);
+                            debug.dump(DebugContext.DETAILED_LEVEL, graph, "FullUnroll %s", loop);
+                            peeled = true;
+                            break;
+                        }
                     }
-                }
-                dataCounted.deleteUnusedNodes();
-            } while (peeled);
+                    dataCounted.deleteUnusedNodes();
+                } while (peeled);
+            }
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,9 +33,9 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.extended.OpaqueNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 public class LoopPartialUnrollPhase extends LoopPhase<LoopPolicies> {
 
@@ -48,7 +48,7 @@
 
     @Override
     @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         if (graph.hasLoops()) {
             EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener();
             boolean changed = true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,7 +29,7 @@
 import org.graalvm.compiler.loop.LoopPolicies;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 
 public class LoopPeelingPhase extends LoopPhase<LoopPolicies> {
 
@@ -39,7 +39,7 @@
 
     @Override
     @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         DebugContext debug = graph.getDebug();
         if (graph.hasLoops()) {
             LoopsData data = new LoopsData(graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,10 +25,10 @@
 package org.graalvm.compiler.loop.phases;
 
 import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public abstract class LoopPhase<P extends LoopPolicies> extends BasePhase<PhaseContext> {
+public abstract class LoopPhase<P extends LoopPolicies> extends BasePhase<CoreProviders> {
     private P policies;
 
     public LoopPhase(P policies) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Fri Jun 28 14:36:42 2019 +0530
@@ -65,8 +65,8 @@
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
 import org.graalvm.compiler.nodes.extended.OpaqueNode;
 import org.graalvm.compiler.nodes.extended.SwitchNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 public abstract class LoopTransformations {
 
@@ -79,7 +79,7 @@
         loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
     }
 
-    public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
+    public static void fullUnroll(LoopEx loop, CoreProviders context, CanonicalizerPhase canonicalizer) {
         // assert loop.isCounted(); //TODO (gd) strengthen : counted with known trip count
         LoopBeginNode loopBegin = loop.loopBegin();
         StructuredGraph graph = loopBegin.graph();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -62,14 +62,14 @@
 public class LoopPartialUnrollTest extends GraalCompilerTest {
 
     @Override
-    protected boolean checkMidTierGraph(StructuredGraph graph) {
+    protected void checkMidTierGraph(StructuredGraph graph) {
         NodeIterable<LoopBeginNode> loops = graph.getNodes().filter(LoopBeginNode.class);
         for (LoopBeginNode loop : loops) {
             if (loop.isMainLoop()) {
-                return true;
+                return;
             }
         }
-        return false;
+        fail("expected a main loop");
     }
 
     public static long sumWithEqualityLimit(int[] text) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Fri Jun 28 14:36:42 2019 +0530
@@ -387,7 +387,7 @@
                 if (loop.isOutsideLoop(op)) {
                     continue;
                 }
-                if (op.usages().count() == 1 && op.usages().first() == baseIvNode) {
+                if (op.hasExactlyOneUsage() && op.usages().first() == baseIvNode) {
                     /*
                      * This is just the base induction variable increment with no other uses so
                      * don't bother reporting it.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.microbenchmarks.graal.util.GraphState;
 import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.openjdk.jmh.annotations.Benchmark;
 
 public class ConditionalEliminationBenchmark extends GraalBenchmark {
@@ -109,12 +108,12 @@
 
     @Benchmark
     public void nullness(Nullness s, GraalState g) {
-        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, g.providers);
     }
 
     @Benchmark
     public void newDominatorConditionalElimination(Nullness s, GraalState g) {
-        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, g.providers);
     }
 
     @MethodSpec(declaringClass = ConditionalEliminationBenchmark.class, name = "searchSnippet")
@@ -165,6 +164,6 @@
 
     @Benchmark
     public void search(Search s, GraalState g) {
-        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, g.providers);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,22 +24,21 @@
 
 package org.graalvm.compiler.nodes.test;
 
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
 
 /**
  * A few tests of expected simplifications by
@@ -156,7 +155,7 @@
     public void test(String name, Class<? extends Node> expectedClass, int expectedCount) {
         StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
 
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         graph.clearAllStateAfter();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,18 +24,17 @@
 
 package org.graalvm.compiler.nodes.test;
 
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.graph.iterators.NodePredicate;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.PhiNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
 public class LoopPhiCanonicalizerTest extends GraalCompilerTest {
 
@@ -66,7 +65,7 @@
         StructuredGraph graph = parseEager("loopSnippet", AllowAssumptions.YES);
         NodePredicate loopPhis = node -> node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode;
 
-        PhaseContext context = new PhaseContext(getProviders());
+        CoreProviders context = getProviders();
         Assert.assertEquals(5, graph.getNodes().filter(loopPhis).count());
         new CanonicalizerPhase().apply(graph, context);
         Assert.assertEquals(2, graph.getNodes().filter(loopPhis).count());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -39,12 +39,12 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -377,7 +377,7 @@
         for (int i = 1; i <= 64; ++i) {
             String snippet = "testCascadeSnippet" + i;
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
             canonicalizer.apply(graph, context);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -512,8 +512,8 @@
 
             if (expectedNode instanceof EndNode) {
                 /* Visit the merge node, which is the one and only usage of the EndNode. */
-                assert expectedNode.usages().count() == 1;
-                assert actualNode.usages().count() == 1;
+                assert expectedNode.hasExactlyOneUsage();
+                assert actualNode.hasExactlyOneUsage();
                 verifyNodesEqual(expectedNode.usages(), actualNode.usages(), nodeMapping, workList, false);
             }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
 import org.graalvm.compiler.bytecode.Bytes;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -56,6 +57,7 @@
 import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.AddNode;
 import org.graalvm.compiler.nodes.calc.CompareNode;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
@@ -295,7 +297,8 @@
             return;
         }
 
-        if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
+        if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode &&
+                        !(((IfNode) falseSuccessor().next()).falseSuccessor() instanceof LoopExitNode)) {
             AbstractBeginNode intermediateBegin = falseSuccessor();
             IfNode nextIf = (IfNode) intermediateBegin.next();
             double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
@@ -465,7 +468,7 @@
                 return false;
             }
             MergeNode merge = (MergeNode) trueEnd.merge();
-            if (merge.usages().count() != 1 || merge.phis().count() != 1) {
+            if (!merge.hasExactlyOneUsage() || merge.phis().count() != 1) {
                 return false;
             }
 
@@ -789,6 +792,7 @@
             ValueNode trueValue = trueEnd.result();
             ValueNode falseValue = falseEnd.result();
             ValueNode value = null;
+            boolean needsProxy = false;
             if (trueValue != null) {
                 if (trueValue == falseValue) {
                     value = trueValue;
@@ -797,8 +801,20 @@
                     if (value == null) {
                         return false;
                     }
+                    needsProxy = true;
                 }
             }
+
+            if (trueSuccessor() instanceof LoopExitNode) {
+                LoopBeginNode loopBegin = ((LoopExitNode) trueSuccessor()).loopBegin();
+                assert loopBegin == ((LoopExitNode) falseSuccessor()).loopBegin();
+                LoopExitNode loopExitNode = graph().add(new LoopExitNode(loopBegin));
+                graph().addBeforeFixed(this, loopExitNode);
+                if (graph().hasValueProxies() && needsProxy) {
+                    value = graph().addOrUnique(new ValueProxyNode(value, loopExitNode));
+                }
+            }
+
             ReturnNode newReturn = graph().add(new ReturnNode(value));
             replaceAtPredecessor(newReturn);
             GraphUtil.killCFG(this);
@@ -834,7 +850,7 @@
                  * we can collapse all proxy nodes on one loop exit, the surviving one, which will
                  * be the true successor
                  */
-                if (falseSuccessor.anchored().isEmpty() && falseSuccessor.usages().isNotEmpty()) {
+                if (falseSuccessor.anchored().isEmpty() && falseSuccessor.hasUsages()) {
                     for (Node n : falseSuccessor.usages().snapshot()) {
                         assert n instanceof ProxyNode;
                         ((ProxyNode) n).setProxyPoint((LoopExitNode) trueSuccessor);
@@ -844,7 +860,7 @@
                  * The true successor (surviving loop exit) can have usages, namely proxy nodes, the
                  * false successor however, must not have usages any more after the code above
                  */
-                assert trueSuccessor.anchored().isEmpty() && falseSuccessor.usages().isEmpty();
+                assert trueSuccessor.anchored().isEmpty() && falseSuccessor.hasNoUsages();
                 return this.graph().addOrUnique(new ValueProxyNode(replacement, (LoopExitNode) trueSuccessor));
             }
         }
@@ -947,16 +963,18 @@
             if (constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant() && condition() instanceof CompareNode &&
                             conditional.condition() instanceof CompareNode) {
 
-                Condition cond1 = ((CompareNode) condition()).condition().asCondition();
+                CompareNode condition1 = (CompareNode) condition();
+                Condition cond1 = condition1.condition().asCondition();
                 if (negateCondition) {
                     cond1 = cond1.negate();
                 }
                 // cond1 is EQ, NE, LT, or GE
-                Condition cond2 = ((CompareNode) conditional.condition()).condition().asCondition();
-                ValueNode x = ((CompareNode) condition()).getX();
-                ValueNode y = ((CompareNode) condition()).getY();
-                ValueNode x2 = ((CompareNode) conditional.condition()).getX();
-                ValueNode y2 = ((CompareNode) conditional.condition()).getY();
+                CompareNode condition2 = (CompareNode) conditional.condition();
+                Condition cond2 = condition2.condition().asCondition();
+                ValueNode x = condition1.getX();
+                ValueNode y = condition1.getY();
+                ValueNode x2 = condition2.getX();
+                ValueNode y2 = condition2.getY();
                 // `x cond1 y ? c1 : (x2 cond2 y2 ? c2 : c3)`
                 boolean sameVars = x == x2 && y == y2;
                 if (!sameVars && x == y2 && y == x2) {
@@ -964,62 +982,89 @@
                     cond2 = cond2.mirror();
                 }
                 if (sameVars) {
+
                     JavaKind stackKind = conditional.trueValue().stamp(NodeView.from(tool)).getStackKind();
                     assert !stackKind.isNumericFloat();
 
-                    ValueNode v1 = constant;
-                    ValueNode v2 = conditional.trueValue();
-                    ValueNode v3 = conditional.falseValue();
+                    long c1 = constant.asJavaConstant().asLong();
+                    long c2 = conditional.trueValue().asJavaConstant().asLong();
+                    long c3 = conditional.falseValue().asJavaConstant().asLong();
 
-                    long c1 = v1.asJavaConstant().asLong();
-                    long c2 = v2.asJavaConstant().asLong();
-                    long c3 = v3.asJavaConstant().asLong();
+                    // canonicalize cond2
+                    cond2 = cond2.join(cond1.negate());
+                    if (cond2 == null) {
+                        // mixing signed and unsigned cases, or useless combination of conditions
+                        return null;
+                    }
+                    // derive cond3 from cond1 and cond2
+                    Condition cond3 = cond1.negate().join(cond2.negate());
+                    if (cond3 == null) {
+                        // mixing signed and unsigned cases, or useless combination of conditions
+                        return null;
+                    }
+                    boolean unsigned = cond1.isUnsigned() || cond2.isUnsigned();
+
+                    long expected1 = expectedConstantForNormalize(cond1);
+                    long expected2 = expectedConstantForNormalize(cond2);
+                    long expected3 = expectedConstantForNormalize(cond3);
 
-                    if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == -1 && c2 == 0 && c3 == 1) {
-                        // x < y ? -1 : (x == y ? 0 : 1) => x cmp y
-                        return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
-                    } else if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == 1 && c2 == 0 && c3 == -1) {
-                        // x < y ? 1 : (x == y ? 0 : -1) => y cmp x
-                        return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
-                    } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == -1 && c3 == 1) {
-                        // x == y ? 0 : (x < y ? -1 : 1) => x cmp y
-                        return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
-                    } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == 1 && c3 == -1) {
-                        // x == y ? 0 : (x < y ? 1 : -1) => y cmp x
-                        return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
-                    } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == -1 && c3 == 1) {
-                        // x == y ? 0 : (x > y ? -1 : 1) => y cmp x
-                        return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
-                    } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == 1 && c3 == -1) {
-                        // x == y ? 0 : (x > y ? 1 : -1) => x cmp y
-                        return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
-                    } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == 1 && c2 == -1 && c3 == 0) {
-                        // x < y ? 1 : (x > y ? -1 : 0) => y cmp x
-                        return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
-                    } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == -1 && c2 == 1 && c3 == 0) {
-                        // x < y ? -1 : (x > y ? 1 : 0) => x cmp y
-                        return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
+                    if (c1 == expected1 && c2 == expected2 && c3 == expected3) {
+                        // normal order
+                    } else if (c1 == 0 - expected1 && c2 == 0 - expected2 && c3 == 0 - expected3) {
+                        // reverse order
+                        ValueNode tmp = x;
+                        x = y;
+                        y = tmp;
+                    } else {
+                        // cannot be expressed by NormalizeCompareNode
+                        return null;
                     }
+                    if (unsigned) {
+                        // for unsigned comparisons, we need to add MIN_VALUE (see
+                        // Long.compareUnsigned)
+                        ValueNode minValue = graph().unique(ConstantNode.forIntegerStamp(x.stamp,
+                                        x.stamp.getStackKind().getMinValue()));
+                        x = graph().unique(new AddNode(x, minValue));
+                        y = graph().unique(new AddNode(y, minValue));
+                    }
+                    boolean unorderedLess = false;
+                    if (x.stamp instanceof FloatStamp && (((FloatStamp) x.stamp).canBeNaN() || ((FloatStamp) y.stamp).canBeNaN())) {
+                        // we may encounter NaNs, check the unordered value
+                        // (following the original condition's "unorderedIsTrue" path)
+                        long unorderedValue = condition1.unorderedIsTrue() ? c1 : condition2.unorderedIsTrue() ? c2 : c3;
+                        if (unorderedValue == 0) {
+                            // returning "0" for unordered is not possible
+                            return null;
+                        }
+                        unorderedLess = unorderedValue == -1;
+                    }
+                    return graph().unique(new NormalizeCompareNode(x, y, stackKind, unorderedLess));
                 }
             }
         }
         return null;
     }
 
+    private static long expectedConstantForNormalize(Condition condition) {
+        if (condition == Condition.EQ) {
+            return 0;
+        } else if (condition == Condition.LT || condition == Condition.BT) {
+            return -1;
+        } else {
+            assert condition == Condition.GT || condition == Condition.AT;
+            return 1;
+        }
+    }
+
     /**
      * Take an if that is immediately dominated by a merge with a single phi and split off any paths
-     * where the test would be statically decidable creating a new merge below the approriate side
+     * where the test would be statically decidable creating a new merge below the appropriate side
      * of the IfNode. Any undecidable tests will continue to use the original IfNode.
      *
      * @param tool
      */
     @SuppressWarnings("try")
     private boolean splitIfAtPhi(SimplifierTool tool) {
-        if (graph().getGuardsStage().areFrameStatesAtSideEffects()) {
-            // Disabled until we make sure we have no FrameState-less merges at this stage
-            return false;
-        }
-
         if (!(predecessor() instanceof MergeNode)) {
             return false;
         }
@@ -1028,15 +1073,14 @@
             // Don't bother.
             return false;
         }
-        if (merge.usages().count() != 1 || merge.phis().count() != 1) {
+        if (merge.getUsageCount() != 1 || merge.phis().count() != 1) {
             return false;
         }
-        if (merge.stateAfter() != null) {
-            /* We'll get the chance to simplify this after frame state assignment. */
+        if (graph().getGuardsStage().areFrameStatesAtSideEffects() && merge.stateAfter() == null) {
             return false;
         }
         PhiNode phi = merge.phis().first();
-        if (phi.usages().count() != 1) {
+        if (phi.getUsageCount() != 1) {
             /*
              * For simplicity the below code assumes assumes the phi goes dead at the end so skip
              * this case.
@@ -1061,7 +1105,6 @@
         /* Each successor of the if gets a new merge if needed. */
         MergeNode trueMerge = null;
         MergeNode falseMerge = null;
-        assert merge.stateAfter() == null;
 
         for (EndNode end : merge.forwardEnds().snapshot()) {
             Node value = phi.valueAt(end);
@@ -1070,12 +1113,12 @@
                 merge.removeEnd(end);
                 if (((LogicConstantNode) result).getValue()) {
                     if (trueMerge == null) {
-                        trueMerge = insertMerge(trueSuccessor());
+                        trueMerge = insertMerge(trueSuccessor(), merge.stateAfter());
                     }
                     trueMerge.addForwardEnd(end);
                 } else {
                     if (falseMerge == null) {
-                        falseMerge = insertMerge(falseSuccessor());
+                        falseMerge = insertMerge(falseSuccessor(), merge.stateAfter());
                     }
                     falseMerge.addForwardEnd(end);
                 }
@@ -1096,13 +1139,13 @@
                 ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
 
                 if (trueMerge == null) {
-                    trueMerge = insertMerge(trueSuccessor());
+                    trueMerge = insertMerge(trueSuccessor(), merge.stateAfter());
                 }
                 trueBegin.setNext(graph().add(new EndNode()));
                 trueMerge.addForwardEnd((EndNode) trueBegin.next());
 
                 if (falseMerge == null) {
-                    falseMerge = insertMerge(falseSuccessor());
+                    falseMerge = insertMerge(falseSuccessor(), merge.stateAfter());
                 }
                 falseBegin.setNext(graph().add(new EndNode()));
                 falseMerge.addForwardEnd((EndNode) falseBegin.next());
@@ -1129,7 +1172,7 @@
      *         dead after the optimization.
      */
     private static boolean conditionUses(LogicNode condition, PhiNode phi) {
-        if (condition.usages().count() != 1) {
+        if (!condition.hasExactlyOneUsage()) {
             return false;
         }
         if (condition instanceof ShortCircuitOrNode) {
@@ -1222,7 +1265,7 @@
     }
 
     @SuppressWarnings("try")
-    private MergeNode insertMerge(AbstractBeginNode begin) {
+    private MergeNode insertMerge(AbstractBeginNode begin, FrameState stateAfter) {
         MergeNode merge = graph().add(new MergeNode());
         if (!begin.anchored().isEmpty()) {
             Object before = null;
@@ -1245,6 +1288,7 @@
         next.replaceAtPredecessor(merge);
         theBegin.setNext(graph().add(new EndNode()));
         merge.addForwardEnd((EndNode) theBegin.next());
+        merge.setStateAfter(stateAfter);
         merge.setNext(next);
         return merge;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri Jun 28 14:36:42 2019 +0530
@@ -678,7 +678,7 @@
         if (node instanceof AbstractBeginNode) {
             ((AbstractBeginNode) node).prepareDelete();
         }
-        assert node.hasNoUsages() : node + " " + node.usages().count() + ", " + node.usages().first();
+        assert node.hasNoUsages() : node + " " + node.getUsageCount() + ", " + node.usages().first();
         GraphUtil.unlinkFixedNode(node);
         node.safeDelete();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ReinterpretNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ReinterpretNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,6 +44,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.serviceprovider.BufferUtil;
 
 import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.JavaKind;
@@ -83,7 +84,7 @@
         ByteBuffer buffer = ByteBuffer.wrap(new byte[c.getSerializedSize()]).order(ByteOrder.nativeOrder());
         c.serialize(buffer);
 
-        buffer.rewind();
+        BufferUtil.asBaseBuffer(buffer).rewind();
         SerializableConstant ret = ((ArithmeticStamp) stamp).deserialize(buffer);
 
         assert !buffer.hasRemaining();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -122,7 +122,7 @@
             ValueNode dividend = forX;
             int log2 = CodeUtil.log2(abs);
             // no rounding if dividend is positive or if its low bits are always 0
-            if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) {
+            if (stampX.canBeNegative() && (stampX.upMask() & (abs - 1)) != 0) {
                 int bits = PrimitiveStamp.getBits(forX.stamp(view));
                 RightShiftNode sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1));
                 UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Fri Jun 28 14:36:42 2019 +0530
@@ -210,7 +210,7 @@
     public static void addDeferredExit(DeferredExit[] deferredExits, Block b) {
         Loop<Block> outermostExited = b.getDominator().getLoop();
         Loop<Block> exitBlockLoop = b.getLoop();
-        assert outermostExited != null;
+        assert outermostExited != null : "Dominator must be in a loop. Possible cause is a missing loop exit node.";
         while (outermostExited.getParent() != null && outermostExited.getParent() != exitBlockLoop) {
             outermostExited = outermostExited.getParent();
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,8 +25,8 @@
 package org.graalvm.compiler.nodes.extended;
 
 import org.graalvm.compiler.graph.NodeInterface;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
 public interface ArrayRangeWrite extends NodeInterface {
@@ -52,5 +52,5 @@
     int getElementStride();
 
     @Override
-    FixedWithNextNode asNode();
+    FixedAccessNode asNode();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -220,7 +220,7 @@
             return false;
         }
         LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
-        if (loadIndexed.usages().count() > 1) {
+        if (loadIndexed.hasMoreThanOneUsage()) {
             /*
              * The array load is necessary for other reasons too, so there is no benefit optimizing
              * the switch.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/ArrayRangeWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+
+@NodeInfo
+public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable {
+
+    public static final NodeClass<ArrayRangeWriteBarrier> TYPE = NodeClass.create(ArrayRangeWriteBarrier.class);
+    @Input ValueNode length;
+
+    private final int elementStride;
+
+    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, AddressNode address, ValueNode length, int elementStride) {
+        super(c, address);
+        this.length = length;
+        this.elementStride = elementStride;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
+    public int getElementStride() {
+        return elementStride;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/BarrierSet.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+
+public interface BarrierSet {
+    void addBarriers(FixedAccessNode n);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/CardTableBarrierSet.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
+import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+
+public class CardTableBarrierSet implements BarrierSet {
+    public CardTableBarrierSet() {
+    }
+
+    @Override
+    public void addBarriers(FixedAccessNode n) {
+        if (n instanceof ReadNode) {
+            // nothing to do
+        } else if (n instanceof WriteNode) {
+            WriteNode write = (WriteNode) n;
+            addWriteBarrier(write, write.value());
+        } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+            LoweredAtomicReadAndWriteNode atomic = (LoweredAtomicReadAndWriteNode) n;
+            addWriteBarrier(atomic, atomic.getNewValue());
+        } else if (n instanceof AbstractCompareAndSwapNode) {
+            AbstractCompareAndSwapNode cmpSwap = (AbstractCompareAndSwapNode) n;
+            addWriteBarrier(cmpSwap, cmpSwap.getNewValue());
+        } else if (n instanceof ArrayRangeWrite) {
+            addArrayRangeBarriers((ArrayRangeWrite) n);
+        } else {
+            GraalError.guarantee(n.getBarrierType() == BarrierType.NONE, "missed a node that requires a GC barrier: %s", n.getClass());
+        }
+    }
+
+    public boolean needsBarrier(FixedAccessNode n) {
+        if (n instanceof ReadNode) {
+            return false;
+        } else if (n instanceof WriteNode) {
+            WriteNode write = (WriteNode) n;
+            return needsWriteBarrier(write, write.value());
+        } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+            LoweredAtomicReadAndWriteNode atomic = (LoweredAtomicReadAndWriteNode) n;
+            return needsWriteBarrier(atomic, atomic.getNewValue());
+        } else if (n instanceof AbstractCompareAndSwapNode) {
+            AbstractCompareAndSwapNode cmpSwap = (AbstractCompareAndSwapNode) n;
+            return needsWriteBarrier(cmpSwap, cmpSwap.getNewValue());
+        } else if (n instanceof ArrayRangeWrite) {
+            return needsWriteBarrier((ArrayRangeWrite) n);
+        } else {
+            GraalError.guarantee(n.getBarrierType() == BarrierType.NONE, "missed a node that requires a GC barrier: %s", n.getClass());
+            return false;
+        }
+    }
+
+    public boolean hasBarrier(FixedAccessNode n) {
+        if (n instanceof ReadNode) {
+            return false;
+        } else if (n instanceof WriteNode) {
+            WriteNode write = (WriteNode) n;
+            return hasWriteBarrier(write);
+        } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+            LoweredAtomicReadAndWriteNode atomic = (LoweredAtomicReadAndWriteNode) n;
+            return hasWriteBarrier(atomic);
+        } else if (n instanceof AbstractCompareAndSwapNode) {
+            AbstractCompareAndSwapNode cmpSwap = (AbstractCompareAndSwapNode) n;
+            return hasWriteBarrier(cmpSwap);
+        } else if (n instanceof ArrayRangeWrite) {
+            return hasWriteBarrier((ArrayRangeWrite) n);
+        } else {
+            GraalError.guarantee(n.getBarrierType() == BarrierType.NONE, "missed a node that requires a GC barrier: %s", n.getClass());
+            return false;
+        }
+    }
+
+    public boolean isMatchingBarrier(FixedAccessNode n, WriteBarrier barrier) {
+        if (n instanceof ReadNode) {
+            return false;
+        } else if (n instanceof WriteNode || n instanceof LoweredAtomicReadAndWriteNode || n instanceof AbstractCompareAndSwapNode || n instanceof ArrayRangeWrite) {
+            return barrier instanceof SerialWriteBarrier && matches(n, (SerialWriteBarrier) barrier);
+        } else {
+            throw GraalError.shouldNotReachHere("Unexpected node: " + n.getClass());
+        }
+    }
+
+    public void addArrayRangeBarriers(ArrayRangeWrite write) {
+        if (needsWriteBarrier(write)) {
+            StructuredGraph graph = write.asNode().graph();
+            SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+            graph.addAfterFixed(write.asNode(), serialArrayRangeWriteBarrier);
+        }
+    }
+
+    private void addWriteBarrier(FixedAccessNode node, ValueNode writtenValue) {
+        if (needsWriteBarrier(node, writtenValue)) {
+            addSerialPostWriteBarrier(node, node.getAddress(), node.graph());
+        }
+    }
+
+    public boolean needsWriteBarrier(FixedAccessNode node, ValueNode writtenValue) {
+        assert !(node instanceof ArrayRangeWrite);
+        HeapAccess.BarrierType barrierType = node.getBarrierType();
+        switch (barrierType) {
+            case NONE:
+                return false;
+            case FIELD:
+            case ARRAY:
+            case UNKNOWN:
+                return writeRequiresBarrier(node, writtenValue);
+            default:
+                throw new GraalError("unexpected barrier type: " + barrierType);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean writeRequiresBarrier(FixedAccessNode node, ValueNode writtenValue) {
+        // Null writes can skip the card mark.
+        return isNonNullObjectValue(writtenValue);
+    }
+
+    public static boolean needsWriteBarrier(ArrayRangeWrite write) {
+        return write.writesObjectArray();
+    }
+
+    private static boolean hasWriteBarrier(FixedAccessNode node) {
+        return node.next() instanceof SerialWriteBarrier && matches(node, (SerialWriteBarrier) node.next());
+    }
+
+    private static boolean hasWriteBarrier(ArrayRangeWrite write) {
+        FixedAccessNode node = write.asNode();
+        return node.next() instanceof SerialArrayRangeWriteBarrier && matches(write, (SerialArrayRangeWriteBarrier) node.next());
+    }
+
+    private static void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, StructuredGraph graph) {
+        boolean precise = node.getBarrierType() != HeapAccess.BarrierType.FIELD;
+        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise)));
+    }
+
+    private static boolean isNonNullObjectValue(ValueNode value) {
+        return value.stamp(NodeView.DEFAULT) instanceof AbstractObjectStamp && !StampTool.isPointerAlwaysNull(value);
+    }
+
+    private static boolean matches(FixedAccessNode node, SerialWriteBarrier barrier) {
+        if (!barrier.usePrecise()) {
+            if (barrier.getAddress() instanceof OffsetAddressNode && node.getAddress() instanceof OffsetAddressNode) {
+                return GraphUtil.unproxify(((OffsetAddressNode) barrier.getAddress()).getBase()) == GraphUtil.unproxify(((OffsetAddressNode) node.getAddress()).getBase());
+            }
+        }
+        return barrier.getAddress() == node.getAddress();
+    }
+
+    private static boolean matches(ArrayRangeWrite node, SerialArrayRangeWriteBarrier barrier) {
+        return barrier.getAddress() == node.getAddress() && node.getLength() == barrier.getLength() && node.getElementStride() == barrier.getElementStride();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ArrayRangePostWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
+public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
+
+    public G1ArrayRangePostWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ArrayRangePreWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
+public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
+
+    public G1ArrayRangePreWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1BarrierSet.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
+import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+public class G1BarrierSet implements BarrierSet {
+    public G1BarrierSet() {
+    }
+
+    @Override
+    public void addBarriers(FixedAccessNode n) {
+        if (n instanceof ReadNode) {
+            addReadNodeBarriers((ReadNode) n);
+        } else if (n instanceof WriteNode) {
+            WriteNode write = (WriteNode) n;
+            addWriteBarriers(write, write.value(), null, true, write.getNullCheck());
+        } else if (n instanceof LoweredAtomicReadAndWriteNode) {
+            LoweredAtomicReadAndWriteNode atomic = (LoweredAtomicReadAndWriteNode) n;
+            addWriteBarriers(atomic, atomic.getNewValue(), null, true, atomic.getNullCheck());
+        } else if (n instanceof AbstractCompareAndSwapNode) {
+            AbstractCompareAndSwapNode cmpSwap = (AbstractCompareAndSwapNode) n;
+            addWriteBarriers(cmpSwap, cmpSwap.getNewValue(), cmpSwap.getExpectedValue(), false, false);
+        } else if (n instanceof ArrayRangeWrite) {
+            addArrayRangeBarriers((ArrayRangeWrite) n);
+        } else {
+            GraalError.guarantee(n.getBarrierType() == BarrierType.NONE, "missed a node that requires a GC barrier: %s", n.getClass());
+        }
+    }
+
+    private static void addReadNodeBarriers(ReadNode node) {
+        if (node.getBarrierType() == HeapAccess.BarrierType.WEAK_FIELD) {
+            StructuredGraph graph = node.graph();
+            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
+            graph.addAfterFixed(node, barrier);
+        }
+    }
+
+    private void addWriteBarriers(FixedAccessNode node, ValueNode writtenValue, ValueNode expectedValue, boolean doLoad, boolean nullCheck) {
+        HeapAccess.BarrierType barrierType = node.getBarrierType();
+        switch (barrierType) {
+            case NONE:
+                // nothing to do
+                break;
+            case FIELD:
+            case ARRAY:
+            case UNKNOWN:
+                if (isObjectValue(writtenValue)) {
+                    StructuredGraph graph = node.graph();
+                    boolean init = node.getLocationIdentity().isInit();
+                    if (!init) {
+                        // The pre barrier does nothing if the value being read is null, so it can
+                        // be explicitly skipped when this is an initializing store.
+                        addG1PreWriteBarrier(node, node.getAddress(), expectedValue, doLoad, nullCheck, graph);
+                    }
+                    if (writeRequiresPostBarrier(node, writtenValue)) {
+                        boolean precise = barrierType != HeapAccess.BarrierType.FIELD;
+                        addG1PostWriteBarrier(node, node.getAddress(), writtenValue, precise, graph);
+                    }
+                }
+                break;
+            default:
+                throw new GraalError("unexpected barrier type: " + barrierType);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    protected boolean writeRequiresPostBarrier(FixedAccessNode initializingWrite, ValueNode writtenValue) {
+        // Without help from the runtime all writes require an explicit post barrier.
+        return true;
+    }
+
+    private static void addArrayRangeBarriers(ArrayRangeWrite write) {
+        if (write.writesObjectArray()) {
+            StructuredGraph graph = write.asNode().graph();
+            if (!write.isInitialization()) {
+                // The pre barrier does nothing if the value being read is null, so it can
+                // be explicitly skipped when this is an initializing store.
+                G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+                graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier);
+            }
+            G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+            graph.addAfterFixed(write.asNode(), g1ArrayRangePostWriteBarrier);
+        }
+    }
+
+    private static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
+        G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck));
+        preBarrier.setStateBefore(node.stateBefore());
+        node.setNullCheck(false);
+        node.setStateBefore(null);
+        graph.addBeforeFixed(node, preBarrier);
+    }
+
+    private static void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
+        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
+        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull)));
+    }
+
+    private static boolean isObjectValue(ValueNode value) {
+        return value.stamp(NodeView.DEFAULT) instanceof AbstractObjectStamp;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1PostWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
+public class G1PostWriteBarrier extends ObjectWriteBarrier {
+
+    public static final NodeClass<G1PostWriteBarrier> TYPE = NodeClass.create(G1PostWriteBarrier.class);
+    protected final boolean alwaysNull;
+
+    public G1PostWriteBarrier(AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
+        this(TYPE, address, value, precise, alwaysNull);
+    }
+
+    private G1PostWriteBarrier(NodeClass<? extends G1PostWriteBarrier> c, AddressNode address, ValueNode value, boolean precise, boolean alwaysNull) {
+        super(c, address, value, precise);
+        this.alwaysNull = alwaysNull;
+    }
+
+    public boolean alwaysNull() {
+        return alwaysNull;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1PreWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
+public final class G1PreWriteBarrier extends ObjectWriteBarrier implements DeoptimizingNode.DeoptBefore {
+
+    public static final NodeClass<G1PreWriteBarrier> TYPE = NodeClass.create(G1PreWriteBarrier.class);
+
+    @OptionalInput(InputType.State) private FrameState stateBefore;
+    private final boolean nullCheck;
+    private final boolean doLoad;
+
+    public G1PreWriteBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad, boolean nullCheck) {
+        super(TYPE, address, expectedObject, true);
+        assert doLoad == (expectedObject == null);
+        this.doLoad = doLoad;
+        this.nullCheck = nullCheck;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+
+    public boolean getNullCheck() {
+        return nullCheck;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return nullCheck;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    @Override
+    public void setStateBefore(FrameState state) {
+        updateUsages(stateBefore, state);
+        stateBefore = state;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/G1ReferentFieldReadBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+/**
+ * The {@code G1ReferentFieldReadBarrier} is added when a read access is performed to the referent
+ * field of a {@link java.lang.ref.Reference} object (through a {@code LoadFieldNode} or an
+ * {@code UnsafeLoadNode}). The return value of the read is passed to the snippet implementing the
+ * read barrier and consequently is added to the SATB queue if the concurrent marker is enabled.
+ */
+@NodeInfo(cycles = CYCLES_64, size = SIZE_64)
+public final class G1ReferentFieldReadBarrier extends ObjectWriteBarrier {
+    public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
+
+    private final boolean doLoad;
+
+    public G1ReferentFieldReadBarrier(AddressNode address, ValueNode expectedObject, boolean doLoad) {
+        super(TYPE, address, expectedObject, true);
+        this.doLoad = doLoad;
+    }
+
+    public ValueNode getExpectedObject() {
+        return getValue();
+    }
+
+    public boolean doLoad() {
+        return doLoad;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/ObjectWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo
+public abstract class ObjectWriteBarrier extends WriteBarrier {
+
+    public static final NodeClass<ObjectWriteBarrier> TYPE = NodeClass.create(ObjectWriteBarrier.class);
+    @OptionalInput protected ValueNode value;
+    protected final boolean precise;
+
+    protected ObjectWriteBarrier(NodeClass<? extends ObjectWriteBarrier> c, AddressNode address, ValueNode value, boolean precise) {
+        super(c, address);
+        this.value = value;
+        this.precise = precise;
+    }
+
+    public ValueNode getValue() {
+        return value;
+    }
+
+    public boolean usePrecise() {
+        return precise;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/SerialArrayRangeWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
+public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
+
+    public SerialArrayRangeWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/SerialWriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_4;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+@NodeInfo(cycles = CYCLES_8, size = SIZE_4)
+public class SerialWriteBarrier extends ObjectWriteBarrier {
+    public static final NodeClass<SerialWriteBarrier> TYPE = NodeClass.create(SerialWriteBarrier.class);
+
+    protected boolean verifyOnly;
+
+    public SerialWriteBarrier(AddressNode address, boolean precise) {
+        this(TYPE, address, precise);
+    }
+
+    protected SerialWriteBarrier(NodeClass<? extends SerialWriteBarrier> c, AddressNode address, boolean precise) {
+        super(c, address, null, precise);
+    }
+
+    public void setVerifyOnly(boolean value) {
+        this.verifyOnly = value;
+    }
+
+    public boolean getVerifyOnly() {
+        return verifyOnly;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/gc/WriteBarrier.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.gc;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+@NodeInfo
+public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<WriteBarrier> TYPE = NodeClass.create(WriteBarrier.class);
+    @Input(InputType.Association) AddressNode address;
+
+    protected WriteBarrier(NodeClass<? extends WriteBarrier> c, AddressNode address) {
+        super(c, StampFactory.forVoid());
+        this.address = address;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        assert graph().getGuardsStage().areFrameStatesAtDeopts();
+        tool.getLowerer().lower(this, tool);
+    }
+
+    public AddressNode getAddress() {
+        return address;
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Fri Jun 28 14:36:42 2019 +0530
@@ -192,7 +192,12 @@
             if (!IS_IN_NATIVE_IMAGE && UseEncodedGraphs.getValue(b.getOptions())) {
                 b.getReplacements().registerMethodSubstitution(this, targetMethod, INLINE_AFTER_PARSING, b.getOptions());
             }
-            StructuredGraph subst = b.getReplacements().getMethodSubstitution(this, targetMethod, INLINE_AFTER_PARSING, StructuredGraph.AllowAssumptions.ifNonNull(b.getAssumptions()), b.getOptions());
+            StructuredGraph subst = b.getReplacements().getMethodSubstitution(this,
+                            targetMethod,
+                            INLINE_AFTER_PARSING,
+                            StructuredGraph.AllowAssumptions.ifNonNull(b.getAssumptions()),
+                            null /* cancellable */,
+                            b.getOptions());
             if (subst == null) {
                 throw new GraalError("No graphs found for substitution %s", this);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -274,4 +274,8 @@
         }
         return null;
     }
+
+    public void setJavaTypeProfile(JavaTypeProfile profile) {
+        this.profile = profile;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@
         super(c, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
     }
 
-    public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
+    public abstract FloatingAccessNode asFloatingNode();
 
     protected boolean forceFixed;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 package org.graalvm.compiler.nodes.memory;
 
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
@@ -43,6 +44,7 @@
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
@@ -60,10 +62,12 @@
  * Reads an {@linkplain FixedAccessNode accessed} value.
  */
 @NodeInfo(nameTemplate = "Read#{p#location/s}", cycles = CYCLES_2, size = SIZE_1)
-public class ReadNode extends FloatableAccessNode implements LIRLowerableAccess, Canonicalizable, Virtualizable, GuardingNode {
+public class ReadNode extends FloatableAccessNode implements LIRLowerableAccess, Canonicalizable, Virtualizable, GuardingNode, MemoryAccess {
 
     public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
 
+    @OptionalInput(Memory) MemoryNode lastLocationAccess;
+
     public ReadNode(AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
         this(TYPE, address, location, stamp, null, barrierType, false, null);
     }
@@ -71,6 +75,18 @@
     protected ReadNode(NodeClass<? extends ReadNode> c, AddressNode address, LocationIdentity location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
                     FrameState stateBefore) {
         super(c, address, location, stamp, guard, barrierType, nullCheck, stateBefore);
+        this.lastLocationAccess = null;
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode newlla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla));
+        lastLocationAccess = newlla;
     }
 
     @Override
@@ -96,7 +112,7 @@
 
     @SuppressWarnings("try")
     @Override
-    public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) {
+    public FloatingAccessNode asFloatingNode() {
         try (DebugCloseable position = withNodeSourcePosition()) {
             return graph().unique(new FloatingReadNode(getAddress(), getLocationIdentity(), lastLocationAccess, stamp(NodeView.DEFAULT), getGuard(), getBarrierType()));
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/IndexAddressNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/IndexAddressNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,12 +43,18 @@
     @Input ValueNode array;
     @Input ValueNode index;
 
+    private final JavaKind arrayKind;
     private final JavaKind elementKind;
 
     public IndexAddressNode(ValueNode array, ValueNode index, JavaKind elementKind) {
+        this(array, index, elementKind, elementKind);
+    }
+
+    public IndexAddressNode(ValueNode array, ValueNode index, JavaKind arrayKind, JavaKind elementKind) {
         super(TYPE);
         this.array = array;
         this.index = index;
+        this.arrayKind = arrayKind;
         this.elementKind = elementKind;
     }
 
@@ -71,6 +77,10 @@
         return Long.MAX_VALUE;
     }
 
+    public JavaKind getArrayKind() {
+        return arrayKind;
+    }
+
     public JavaKind getElementKind() {
         return elementKind;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java	Fri Jun 28 14:36:42 2019 +0530
@@ -45,4 +45,6 @@
     StampProvider getStampProvider();
 
     ForeignCallsProvider getForeignCalls();
+
+    GCProvider getGC();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersDelegate.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class CoreProvidersDelegate implements CoreProviders {
+
+    private final CoreProviders providers;
+
+    protected CoreProvidersDelegate(CoreProviders providers) {
+        this.providers = providers;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return providers.getConstantReflection();
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return providers.getConstantFieldProvider();
+    }
+
+    @Override
+    public LoweringProvider getLowerer() {
+        return providers.getLowerer();
+    }
+
+    @Override
+    public Replacements getReplacements() {
+        return providers.getReplacements();
+    }
+
+    @Override
+    public StampProvider getStampProvider() {
+        return providers.getStampProvider();
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return providers.getForeignCalls();
+    }
+
+    @Override
+    public GCProvider getGC() {
+        return providers.getGC();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,9 +38,10 @@
     protected final Replacements replacements;
     protected final StampProvider stampProvider;
     protected final ForeignCallsProvider foreignCalls;
+    protected final GCProvider gc;
 
     protected CoreProvidersImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer,
-                    Replacements replacements, StampProvider stampProvider, ForeignCallsProvider foreignCalls) {
+                    Replacements replacements, StampProvider stampProvider, ForeignCallsProvider foreignCalls, GCProvider gc) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.constantFieldProvider = constantFieldProvider;
@@ -48,6 +49,7 @@
         this.replacements = replacements;
         this.stampProvider = stampProvider;
         this.foreignCalls = foreignCalls;
+        this.gc = gc;
     }
 
     @Override
@@ -84,4 +86,9 @@
     public ForeignCallsProvider getForeignCalls() {
         return foreignCalls;
     }
+
+    @Override
+    public GCProvider getGC() {
+        return gc;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,6 +29,7 @@
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderPlugin;
@@ -76,8 +77,8 @@
 
     @Override
     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
-                    StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
-        return delegate.getMethodSubstitution(plugin, original, context, allowAssumptions, options);
+                    StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
+        return delegate.getMethodSubstitution(plugin, original, context, allowAssumptions, cancellable, options);
     }
 
     @Override
@@ -91,8 +92,8 @@
     }
 
     @Override
-    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) {
-        return delegate.getIntrinsicGraph(method, compilationId, debug);
+    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug, Cancellable cancellable) {
+        return delegate.getIntrinsicGraph(method, compilationId, debug, cancellable);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/GCProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.nodes.spi;
+
+import org.graalvm.compiler.nodes.gc.BarrierSet;
+
+public interface GCProvider {
+    /** Returns the barrier set that is used to insert the needed read/write barriers. */
+    BarrierSet getBarrierSet();
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Fri Jun 28 14:36:42 2019 +0530
@@ -30,6 +30,7 @@
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderPlugin;
@@ -86,11 +87,12 @@
      * @param original the method being substituted
      * @param context the kind of inlining to be performed for the substitution
      * @param allowAssumptions
+     * @param cancellable
      * @param options
      * @return the method substitution graph, if any, that is derived from {@code method}
      */
     StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
-                    StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options);
+                    StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options);
 
     /**
      * Registers a plugin as a substitution.
@@ -115,9 +117,10 @@
      * @param method
      * @param compilationId
      * @param debug
+     * @param cancellable
      * @return an intrinsic graph that can be compiled and installed for {@code method} or null
      */
-    StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug);
+    StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug, Cancellable cancellable);
 
     /**
      * Determines if there may be a
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/Option.java	Fri Jun 28 14:36:42 2019 +0530
@@ -64,4 +64,9 @@
      * Specifies the type of the option.
      */
     OptionType type() default OptionType.Debug;
+
+    /**
+     * Specifies the stability of the option.
+     */
+    OptionStability stability() default OptionStability.EXPERIMENTAL;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionStability.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.options;
+
+/**
+ * Categorizes options according to their stability.
+ */
+public enum OptionStability {
+
+    /**
+     * A stable option is expected to remain available for many releases. End users can rely on such
+     * an option being present. A stable option can still be removed but will go through a clear
+     * deprecating process before being removed.
+     */
+    STABLE,
+
+    /**
+     * An experimental option has no guarantees of stability and might be removed at any point.
+     */
+    EXPERIMENTAL
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Fri Jun 28 14:36:42 2019 +0530
@@ -67,15 +67,12 @@
              */
             loader = ClassLoader.getSystemClassLoader();
         }
-        Iterable<OptionDescriptors> result = ServiceLoader.load(OptionDescriptors.class, loader);
-        if (IS_BUILDING_NATIVE_IMAGE) {
-            ArrayList<OptionDescriptors> optionDescriptors = new ArrayList<>();
-            for (OptionDescriptors descriptors : result) {
-                optionDescriptors.add(descriptors);
-            }
-            OptionsParser.cachedOptionDescriptors = optionDescriptors;
-        }
-        return result;
+        return ServiceLoader.load(OptionDescriptors.class, loader);
+    }
+
+    public static void setCachedOptionDescriptors(List<OptionDescriptors> cachedOptionDescriptors) {
+        assert IS_BUILDING_NATIVE_IMAGE : "Used to pre-initialize the option descriptors during native image generation";
+        OptionsParser.cachedOptionDescriptors = cachedOptionDescriptors;
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.ControlSinkNode;
@@ -52,18 +53,18 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.Phase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.MetaAccessProvider;
 
-public class CanonicalizerPhase extends BasePhase<PhaseContext> {
+public class CanonicalizerPhase extends BasePhase<CoreProviders> {
 
     private static final int MAX_ITERATION_PER_NODE = 10;
     private static final CounterKey COUNTER_CANONICALIZED_NODES = DebugContext.counter("CanonicalizedNodes");
@@ -121,7 +122,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         new Instance(context).run(graph);
     }
 
@@ -129,11 +130,11 @@
      * @param newNodesMark only the {@linkplain Graph#getNewNodes(Mark) new nodes} specified by this
      *            mark are processed
      */
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Mark newNodesMark) {
         applyIncremental(graph, context, newNodesMark, true);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Mark newNodesMark, boolean dumpGraph) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Mark newNodesMark, boolean dumpGraph) {
         new Instance(context, newNodesMark).apply(graph, dumpGraph);
     }
 
@@ -141,19 +142,19 @@
      * @param workingSet the initial working set of nodes on which the canonicalizer works, should
      *            be an auto-grow node bitmap
      */
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Iterable<? extends Node> workingSet) {
         applyIncremental(graph, context, workingSet, true);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, boolean dumpGraph) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Iterable<? extends Node> workingSet, boolean dumpGraph) {
         new Instance(context, workingSet).apply(graph, dumpGraph);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
         applyIncremental(graph, context, workingSet, newNodesMark, true);
     }
 
-    public void applyIncremental(StructuredGraph graph, PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark, boolean dumpGraph) {
+    public void applyIncremental(StructuredGraph graph, CoreProviders context, Iterable<? extends Node> workingSet, Mark newNodesMark, boolean dumpGraph) {
         new Instance(context, workingSet, newNodesMark).apply(graph, dumpGraph);
     }
 
@@ -164,26 +165,26 @@
     private final class Instance extends Phase {
 
         private final Mark newNodesMark;
-        private final PhaseContext context;
+        private final CoreProviders context;
         private final Iterable<? extends Node> initWorkingSet;
 
         private NodeWorkList workList;
         private Tool tool;
         private DebugContext debug;
 
-        private Instance(PhaseContext context) {
+        private Instance(CoreProviders context) {
             this(context, null, null);
         }
 
-        private Instance(PhaseContext context, Iterable<? extends Node> workingSet) {
+        private Instance(CoreProviders context, Iterable<? extends Node> workingSet) {
             this(context, workingSet, null);
         }
 
-        private Instance(PhaseContext context, Mark newNodesMark) {
+        private Instance(CoreProviders context, Mark newNodesMark) {
             this(context, null, newNodesMark);
         }
 
-        private Instance(PhaseContext context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
+        private Instance(CoreProviders context, Iterable<? extends Node> workingSet, Mark newNodesMark) {
             this.newNodesMark = newNodesMark;
             this.context = context;
             this.initWorkingSet = workingSet;
@@ -207,12 +208,14 @@
             if (!wholeGraph) {
                 workList.addAll(graph.getNewNodes(newNodesMark));
             }
+
             tool = new Tool(graph.getAssumptions(), graph.getOptions());
             processWorkSet(graph);
         }
 
         @SuppressWarnings("try")
-        private void processWorkSet(StructuredGraph graph) {
+        private int processWorkSet(StructuredGraph graph) {
+            int sum = 0;
             NodeEventListener listener = new NodeEventListener() {
 
                 @Override
@@ -228,6 +231,13 @@
                             workList.add(usage);
                         }
                     }
+
+                    if (node instanceof AbstractBeginNode) {
+                        AbstractBeginNode abstractBeginNode = (AbstractBeginNode) node;
+                        if (abstractBeginNode.predecessor() != null) {
+                            workList.add(abstractBeginNode.predecessor());
+                        }
+                    }
                 }
 
                 @Override
@@ -242,8 +252,10 @@
                     if (changed && debug.isDumpEnabled(DebugContext.DETAILED_LEVEL)) {
                         debug.dump(DebugContext.DETAILED_LEVEL, graph, "CanonicalizerPhase %s", n);
                     }
+                    ++sum;
                 }
             }
+            return sum;
         }
 
         /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -56,6 +56,7 @@
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.BinaryOpLogicNode;
 import org.graalvm.compiler.nodes.ConditionAnchorNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
 import org.graalvm.compiler.nodes.DeoptimizingGuard;
 import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
@@ -90,20 +91,20 @@
 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.nodes.java.TypeSwitchNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.NodeWithState;
 import org.graalvm.compiler.nodes.spi.StampInverter;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.SpeculationLog.Speculation;
 import jdk.vm.ci.meta.TriState;
 
-public class ConditionalEliminationPhase extends BasePhase<PhaseContext> {
+public class ConditionalEliminationPhase extends BasePhase<CoreProviders> {
 
     private static final CounterKey counterStampsRegistered = DebugContext.counter("StampsRegistered");
     private static final CounterKey counterStampsFound = DebugContext.counter("StampsFound");
@@ -123,7 +124,7 @@
 
     @Override
     @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         try (DebugContext.Scope s = graph.getDebug().scope("DominatorConditionalElimination")) {
             BlockMap<List<Node>> blockToNodes = null;
             NodeMap<Block> nodeToBlock = null;
@@ -154,7 +155,7 @@
     }
 
     protected ControlFlowGraph.RecursiveVisitor<?> createVisitor(StructuredGraph graph, @SuppressWarnings("unused") ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes,
-                    NodeMap<Block> nodeToBlock, PhaseContext context) {
+                    NodeMap<Block> nodeToBlock, CoreProviders context) {
         return new Instance(graph, blockToNodes, nodeToBlock, context);
     }
 
@@ -302,7 +303,7 @@
          */
         private Deque<DeoptimizingGuard> pendingTests;
 
-        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, PhaseContext context) {
+        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, CoreProviders context) {
             this.graph = graph;
             this.debug = graph.getDebug();
             this.blockToNodes = blockToNodes;
@@ -335,19 +336,26 @@
             if (!tryProveGuardCondition(node, node.getCondition(), (guard, result, guardedValueStamp, newInput) -> {
                 if (result != node.isNegated()) {
                     node.replaceAndDelete(guard.asNode());
+                    if (guard instanceof DeoptimizingGuard && !((DeoptimizingGuard) guard).isNegated()) {
+                        rebuildPiNodes((DeoptimizingGuard) guard);
+                    }
                 } else {
-                    /*
-                     * Don't kill this branch immediately because `killCFG` can have complex
-                     * implications in the presence of loops: it might replace or delete nodes in
-                     * other branches or even above the kill point. Instead of killing immediately,
-                     * just leave the graph in a state that is easy to simplify by a subsequent
-                     * canonicalizer phase.
-                     */
-                    FixedGuardNode deopt = new FixedGuardNode(LogicConstantNode.forBoolean(result, node.graph()), node.getReason(), node.getAction(), node.getSpeculation(), node.isNegated(),
-                                    node.getNodeSourcePosition());
                     AbstractBeginNode beginNode = (AbstractBeginNode) node.getAnchor();
-                    graph.addAfterFixed(beginNode, node.graph().add(deopt));
 
+                    if (beginNode.next() instanceof DeoptimizeNode) {
+                        // This branch is already dead.
+                    } else {
+                        /*
+                         * Don't kill this branch immediately because `killCFG` can have complex
+                         * implications in the presence of loops: it might replace or delete nodes
+                         * in other branches or even above the kill point. Instead of killing
+                         * immediately, just leave the graph in a state that is easy to simplify by
+                         * a subsequent canonicalizer phase.
+                         */
+                        FixedGuardNode deopt = new FixedGuardNode(LogicConstantNode.forBoolean(result, node.graph()), node.getReason(), node.getAction(), node.getSpeculation(), node.isNegated(),
+                                        node.getNodeSourcePosition());
+                        graph.addAfterFixed(beginNode, node.graph().add(deopt));
+                    }
                 }
                 return true;
             })) {
@@ -361,41 +369,14 @@
                     node.replaceAtUsages(guard.asNode());
                     GraphUtil.unlinkFixedNode(node);
                     GraphUtil.killWithUnusedFloatingInputs(node);
+                    if (guard instanceof DeoptimizingGuard && !((DeoptimizingGuard) guard).isNegated()) {
+                        rebuildPiNodes((DeoptimizingGuard) guard);
+                    }
                 } else {
                     node.setCondition(LogicConstantNode.forBoolean(result, node.graph()), node.isNegated());
                     // Don't kill this branch immediately, see `processGuard`.
                 }
 
-                if (guard instanceof DeoptimizingGuard && !node.isNegated() && !((DeoptimizingGuard) guard).isNegated()) {
-                    LogicNode newCondition = ((DeoptimizingGuard) guard.asNode()).getCondition();
-                    if (newCondition instanceof InstanceOfNode) {
-                        InstanceOfNode inst = (InstanceOfNode) newCondition;
-                        ValueNode originalValue = GraphUtil.skipPi(inst.getValue());
-                        PiNode pi = null;
-                        // Ensure that any Pi that's weaker than what the instanceof proves is
-                        // replaced by one derived from the instanceof itself.
-                        for (PiNode existing : guard.asNode().usages().filter(PiNode.class).snapshot()) {
-                            if (!existing.isAlive()) {
-                                continue;
-                            }
-                            if (originalValue != GraphUtil.skipPi(existing.object())) {
-                                // Somehow these are unrelated values so leave it alone
-                                continue;
-                            }
-                            // If the pi has a weaker stamp or the same stamp but a different input
-                            // then replace it.
-                            boolean strongerStamp = !existing.piStamp().join(inst.getCheckedStamp()).equals(inst.getCheckedStamp());
-                            boolean differentStamp = !existing.piStamp().equals(inst.getCheckedStamp());
-                            boolean differentObject = existing.object() != inst.getValue();
-                            if (!strongerStamp && (differentStamp || differentObject)) {
-                                if (pi == null) {
-                                    pi = graph.unique(new PiNode(inst.getValue(), inst.getCheckedStamp(), (ValueNode) guard));
-                                }
-                                existing.replaceAndDelete(pi);
-                            }
-                        }
-                    }
-                }
                 debug.log("Kill fixed guard %s", node);
                 return true;
             })) {
@@ -403,6 +384,59 @@
             }
         }
 
+        private void rebuildPiNodes(DeoptimizingGuard guard) {
+            LogicNode newCondition = guard.getCondition();
+            if (newCondition instanceof InstanceOfNode) {
+                InstanceOfNode inst = (InstanceOfNode) newCondition;
+                ValueNode originalValue = GraphUtil.skipPi(inst.getValue());
+                PiNode pi = null;
+                // Ensure that any Pi that's weaker than what the instanceof proves is
+                // replaced by one derived from the instanceof itself.
+                for (PiNode existing : guard.asNode().usages().filter(PiNode.class).snapshot()) {
+                    if (!existing.isAlive()) {
+                        continue;
+                    }
+                    if (originalValue != GraphUtil.skipPi(existing.object())) {
+                        // Somehow these are unrelated values so leave it alone
+                        continue;
+                    }
+                    // If the pi has a weaker stamp or the same stamp but a different input
+                    // then replace it.
+                    boolean strongerStamp = !existing.piStamp().join(inst.getCheckedStamp()).equals(inst.getCheckedStamp());
+                    boolean differentCheckedStamp = !existing.piStamp().equals(inst.getCheckedStamp());
+                    boolean differentObject = existing.object() != inst.getValue();
+                    if (!strongerStamp && (differentCheckedStamp || differentObject)) {
+                        if (pi == null) {
+                            pi = graph.unique(new PiNode(inst.getValue(), inst.getCheckedStamp(), (ValueNode) guard));
+                        }
+                        if (!pi.stamp(NodeView.DEFAULT).join(existing.stamp(NodeView.DEFAULT)).equals(pi.stamp(NodeView.DEFAULT))) {
+                            /*
+                             * With a code sequence like null check, type check, null check of type
+                             * checked value, CE will use the first null check to prove the second
+                             * null check so the graph ends up a Pi guarded by the first null check
+                             * but consuming the output Pi from the type check check. In this case
+                             * we should still canonicalize the checked stamp for consistency.
+                             */
+                            if (differentCheckedStamp) {
+                                PiNode alternatePi = graph.unique(new PiNode(existing.object(), inst.getCheckedStamp(), (ValueNode) guard));
+                                /*
+                                 * If the resulting stamp is as good or better then do the
+                                 * replacement. However when interface types are involved it's
+                                 * possible that improving the checked stamp merges types which
+                                 * appear unrelated so there's we must skip the replacement.
+                                 */
+                                if (alternatePi.stamp(NodeView.DEFAULT).join(existing.stamp(NodeView.DEFAULT)).equals(alternatePi.stamp(NodeView.DEFAULT))) {
+                                    existing.replaceAndDelete(alternatePi);
+                                }
+                            }
+                            continue;
+                        }
+                        existing.replaceAndDelete(pi);
+                    }
+                }
+            }
+        }
+
         protected void processIf(IfNode node) {
             tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
                 node.setCondition(LogicConstantNode.forBoolean(result, node.graph()));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -69,6 +69,7 @@
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
 import org.graalvm.compiler.nodes.memory.MemoryAccess;
 import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
@@ -77,7 +78,6 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.Constant;
@@ -638,7 +638,7 @@
         }
     }
 
-    protected ControlFlowGraph.RecursiveVisitor<?> createVisitor(StructuredGraph graph, ScheduleResult schedule, PhaseContext context) {
+    protected ControlFlowGraph.RecursiveVisitor<?> createVisitor(StructuredGraph graph, ScheduleResult schedule, CoreProviders context) {
         return new RawConditionalEliminationVisitor(graph, schedule, context.getMetaAccess(), replaceInputsWithConstants);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -381,7 +381,8 @@
                 assert accessNode.getNullCheck() == false;
                 MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity);
                 try (DebugCloseable position = accessNode.withNodeSourcePosition()) {
-                    FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess);
+                    FloatingAccessNode floatingNode = accessNode.asFloatingNode();
+                    assert floatingNode.getLastLocationAccess() == lastLocationAccess;
                     graph.replaceFixedWithFloating(accessNode, floatingNode);
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -26,16 +26,16 @@
 
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 /**
  * A phase suite that applies {@linkplain CanonicalizerPhase canonicalization} to a graph after all
  * phases in the suite have been applied if any of the phases changed the graph.
  */
-public class IncrementalCanonicalizerPhase<C extends PhaseContext> extends PhaseSuite<C> {
+public class IncrementalCanonicalizerPhase<C extends CoreProviders> extends PhaseSuite<C> {
 
     private final CanonicalizerPhase canonicalizer;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,20 +24,21 @@
 
 package org.graalvm.compiler.phases.common;
 
-import static org.graalvm.compiler.graph.Graph.NodeEvent.NODE_ADDED;
-
-import org.graalvm.compiler.core.common.RetryableBailoutException;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.phases.common.util.TracingNodeEventListener;
 
-public class IterativeConditionalEliminationPhase extends BasePhase<PhaseContext> {
+public class IterativeConditionalEliminationPhase extends BasePhase<CoreProviders> {
 
-    private static final int MAX_ITERATIONS = 256;
+    private static final boolean DEBUG_PHASE = false;
+    private static final int DEBUG_MAX_ITERATIONS = 256;
 
     private final CanonicalizerPhase canonicalizer;
     private final boolean fullSchedule;
@@ -49,25 +50,46 @@
 
     @Override
     @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener().exclude(NODE_ADDED);
+    protected void run(StructuredGraph graph, CoreProviders context) {
+        final int maxIterations = GraalOptions.ConditionalEliminationMaxIterations.getValue(graph.getOptions());
+        EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener();
         int count = 0;
+
         while (true) {
+            count++;
             try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
                 new ConditionalEliminationPhase(fullSchedule).apply(graph, context);
             }
             if (listener.getNodes().isEmpty()) {
                 break;
             }
-            for (Node node : graph.getNodes()) {
-                if (node instanceof Simplifiable) {
-                    listener.getNodes().add(node);
-                }
-            }
+
             canonicalizer.applyIncremental(graph, context, listener.getNodes());
             listener.getNodes().clear();
-            if (++count > MAX_ITERATIONS) {
-                throw new RetryableBailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds %d", MAX_ITERATIONS);
+
+            if (count >= maxIterations) {
+                if (DEBUG_PHASE) {
+                    if (count >= DEBUG_MAX_ITERATIONS - 5) {
+                        TTY.println();
+                        TTY.println("------------------------------------");
+                        TTY.println("Iteration " + count);
+                        TTY.println("Conditional elimination changed nodes: ");
+                        for (Node n : listener.getNodes()) {
+                            TTY.println(n.toString());
+                            for (Node input : n.inputs()) {
+                                TTY.println("    input: " + input);
+                            }
+                        }
+                        TTY.println("Canonicalization with node listener: ");
+                        try (NodeEventScope debugNes = graph.trackNodeEvents(new TracingNodeEventListener())) {
+                            canonicalizer.applyIncremental(graph, context, listener.getNodes());
+                        }
+                    }
+                    if (count >= DEBUG_MAX_ITERATIONS) {
+                        throw new PermanentBailoutException("Number of iterations in ConditionalEliminationPhase phase exceeds %d", DEBUG_MAX_ITERATIONS);
+                    }
+                }
+                break;
             }
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -79,7 +79,6 @@
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.Phase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -92,7 +91,7 @@
 /**
  * Processes all {@link Lowerable} nodes to do their lowering.
  */
-public class LoweringPhase extends BasePhase<PhaseContext> {
+public class LoweringPhase extends BasePhase<CoreProviders> {
 
     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
     static final class DummyGuardHandle extends ValueNode implements GuardedNode {
@@ -128,12 +127,12 @@
 
     final class LoweringToolImpl implements LoweringTool {
 
-        private final PhaseContext context;
+        private final CoreProviders context;
         private final NodeBitMap activeGuards;
         private AnchoringNode guardAnchor;
         private FixedWithNextNode lastFixedNode;
 
-        LoweringToolImpl(PhaseContext context, AnchoringNode guardAnchor, NodeBitMap activeGuards, FixedWithNextNode lastFixedNode) {
+        LoweringToolImpl(CoreProviders context, AnchoringNode guardAnchor, NodeBitMap activeGuards, FixedWithNextNode lastFixedNode) {
             this.context = context;
             this.guardAnchor = guardAnchor;
             this.activeGuards = activeGuards;
@@ -252,7 +251,7 @@
      * @param graph a graph that was just {@linkplain #lower lowered}
      * @throws AssertionError if the check fails
      */
-    private boolean checkPostLowering(StructuredGraph graph, PhaseContext context) {
+    private boolean checkPostLowering(StructuredGraph graph, CoreProviders context) {
         Mark expectedMark = graph.getMark();
         lower(graph, context, LoweringMode.VERIFY_LOWERING);
         Mark mark = graph.getMark();
@@ -261,13 +260,13 @@
     }
 
     @Override
-    protected void run(final StructuredGraph graph, PhaseContext context) {
+    protected void run(final StructuredGraph graph, CoreProviders context) {
         lower(graph, context, LoweringMode.LOWERING);
         assert checkPostLowering(graph, context);
     }
 
-    private void lower(StructuredGraph graph, PhaseContext context, LoweringMode mode) {
-        IncrementalCanonicalizerPhase<PhaseContext> incrementalCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
+    private void lower(StructuredGraph graph, CoreProviders context, LoweringMode mode) {
+        IncrementalCanonicalizerPhase<CoreProviders> incrementalCanonicalizer = new IncrementalCanonicalizerPhase<>(canonicalizer);
         incrementalCanonicalizer.appendPhase(new Round(context, mode, graph.getOptions()));
         incrementalCanonicalizer.apply(graph, context);
         assert graph.verify();
@@ -351,12 +350,12 @@
 
     private final class Round extends Phase {
 
-        private final PhaseContext context;
+        private final CoreProviders context;
         private final LoweringMode mode;
         private ScheduleResult schedule;
         private final SchedulePhase schedulePhase;
 
-        private Round(PhaseContext context, LoweringMode mode, OptionValues options) {
+        private Round(CoreProviders context, LoweringMode mode, OptionValues options) {
             this.context = context;
             this.mode = mode;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,13 +27,13 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public class NodeCounterPhase extends BasePhase<PhaseContext> {
+public class NodeCounterPhase extends BasePhase<CoreProviders> {
 
     private Stage stage;
 
@@ -55,7 +55,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
 
         for (Node node : graph.getNodes()) {
             String nodeName = node.getNodeClass().getClazz().getSimpleName();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,18 +35,18 @@
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 /**
  * This phase will make sure that the branch leading towards this deopt has 0.0 probability.
  *
  */
-public class PropagateDeoptimizeProbabilityPhase extends BasePhase<PhaseContext> {
+public class PropagateDeoptimizeProbabilityPhase extends BasePhase<CoreProviders> {
 
     @Override
     @SuppressWarnings("try")
-    protected void run(final StructuredGraph graph, PhaseContext context) {
+    protected void run(final StructuredGraph graph, CoreProviders context) {
         assert !graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
 
         if (graph.hasNode(AbstractDeoptimizeNode.TYPE)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -41,6 +41,7 @@
 import org.graalvm.compiler.nodes.DeoptimizeNode;
 import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
 import org.graalvm.compiler.nodes.DynamicDeoptimizeNode;
+import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.LogicNode;
@@ -115,6 +116,7 @@
                 reasons = reasonPhi.values().snapshot();
                 expectedPhis++;
             } else if (!reason.isConstant()) {
+                merge.getDebug().log("Non constant reason %s", merge);
                 return;
             }
 
@@ -135,29 +137,41 @@
             }
 
             int index = 0;
-            for (AbstractEndNode end : merge.cfgPredecessors().snapshot()) {
+            List<EndNode> predecessors = merge.cfgPredecessors().snapshot();
+            for (AbstractEndNode end : predecessors) {
+                Node endPredecesssor = end.predecessor();
                 ValueNode thisReason = reasons != null ? reasons.get(index) : reason;
                 ValueNode thisSpeculation = speculations != null ? speculations.get(index) : speculation;
+                if (!merge.isAlive()) {
+                    // When evacuating a merge the last successor simplfies the merge away so it
+                    // must be handled specially.
+                    assert predecessors.get(predecessors.size() - 1) == end : "must be last end";
+                    endPredecesssor = deopt.predecessor();
+                    thisSpeculation = deopt.getSpeculation();
+                    thisReason = deopt.getActionAndReason();
+                }
+
                 index++;
                 if (!thisReason.isConstant() || !thisSpeculation.isConstant()) {
-                    continue;
-                }
-                Speculation speculationConstant = metaAccessProvider.decodeSpeculation(thisSpeculation.asJavaConstant(), deopt.graph().getSpeculationLog());
-                if (!speculationConstant.equals(SpeculationLog.NO_SPECULATION)) {
+                    end.getDebug().log("Non constant deopt %s", end);
                     continue;
                 }
                 DeoptimizationReason deoptimizationReason = metaAccessProvider.decodeDeoptReason(thisReason.asJavaConstant());
-                tryUseTrappingNullCheck(deopt, end.predecessor(), deoptimizationReason, SpeculationLog.NO_SPECULATION, implicitNullCheckLimit);
+                Speculation speculationConstant = metaAccessProvider.decodeSpeculation(thisSpeculation.asJavaConstant(), deopt.graph().getSpeculationLog());
+                tryUseTrappingNullCheck(deopt, endPredecesssor, deoptimizationReason, speculationConstant, implicitNullCheckLimit);
             }
         }
     }
 
     private static void tryUseTrappingNullCheck(AbstractDeoptimizeNode deopt, Node predecessor, DeoptimizationReason deoptimizationReason, Speculation speculation, long implicitNullCheckLimit) {
+        assert predecessor != null;
         if (deoptimizationReason != DeoptimizationReason.NullCheckException && deoptimizationReason != DeoptimizationReason.UnreachedCode) {
+            deopt.getDebug().log(DebugContext.INFO_LEVEL, "Not a null check or unreached %s", predecessor);
             return;
         }
         assert speculation != null;
         if (!speculation.equals(SpeculationLog.NO_SPECULATION)) {
+            deopt.getDebug().log(DebugContext.INFO_LEVEL, "Has a speculation %s", predecessor);
             return;
         }
         if (predecessor instanceof AbstractMergeNode) {
@@ -169,6 +183,8 @@
             }
         } else if (predecessor instanceof AbstractBeginNode) {
             checkPredecessor(deopt, predecessor, deoptimizationReason, implicitNullCheckLimit);
+        } else {
+            deopt.getDebug().log(DebugContext.INFO_LEVEL, "Not a Begin or Merge %s", predecessor);
         }
     }
 
@@ -233,6 +249,7 @@
                         deopt.graph().removeSplit(ifNode, nonTrappingContinuation);
                         trappingNullCheck = fixedAccessNode;
                         counterTrappingNullCheckExistingRead.increment(debug);
+                        deopt.getDebug().log("Added implicit null check to %s", fixedAccessNode);
                     }
                 }
             }
@@ -242,6 +259,7 @@
             // Need to add a null check node.
             trappingNullCheck = deopt.graph().add(new NullCheckNode(value));
             deopt.graph().replaceSplit(ifNode, trappingNullCheck, nonTrappingContinuation);
+            deopt.getDebug().log("Inserted NullCheckNode %s", trappingNullCheck);
         }
 
         trappingNullCheck.setStateBefore(deopt.stateBefore());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/WriteBarrierAdditionPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.gc.BarrierSet;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.MidTierContext;
+
+public class WriteBarrierAdditionPhase extends BasePhase<MidTierContext> {
+    @SuppressWarnings("try")
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        BarrierSet barrierSet = context.getGC().getBarrierSet();
+        for (FixedAccessNode n : graph.getNodes().filter(FixedAccessNode.class)) {
+            try (DebugCloseable scope = n.graph().withNodeSourcePosition(n)) {
+                barrierSet.addBarriers(n);
+            }
+        }
+    }
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri Jun 28 14:36:42 2019 +0530
@@ -381,7 +381,7 @@
             throw new IllegalStateException("Inlined graph is in invalid state: " + inlineGraph);
         }
         for (Node node : inlineGraph.getNodes()) {
-            if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.usages().count() == 1) || node instanceof ParameterNode) {
+            if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.hasExactlyOneUsage()) || node instanceof ParameterNode) {
                 // Do nothing.
             } else {
                 nodes.add(node);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,11 @@
         OptionValues options = rootGraph.getOptions();
         if (method == null) {
             return "the method is not resolved";
-        } else if (method.isNative() && (!Intrinsify.getValue(options) || !context.getReplacements().hasSubstitution(method, invokeBci))) {
+        } else if (method.isNative() && !(Intrinsify.getValue(options) &&
+                        context.getReplacements().getSubstitution(method, invokeBci, rootGraph.trackNodeSourcePosition(), null, options) != null)) {
+            // We have conditional intrinsic, e.g., String.intern, which may not have inlineable
+            // graph depending on the context. The getSubstitution test ensures the inlineable
+            // graph is present.
             return "it is a non-intrinsic native method";
         } else if (method.isAbstract()) {
             return "it is an abstract method";
@@ -155,8 +159,6 @@
             return "it is marked non-inlinable";
         } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue(options)) {
             return "it exceeds the maximum recursive inlining depth";
-        } else if (!method.hasBytecodes()) {
-            return "it has no bytecodes to inline";
         } else {
             if (new OptimisticOptimizations(rootGraph.getProfilingInfo(method), options).lessOptimisticThan(context.getOptimisticOptimizations())) {
                 return "the callee uses less optimistic optimizations than caller";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,6 +33,7 @@
 import org.graalvm.compiler.graph.Graph.NodeEventListener;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
 
 /**
  * A simple {@link NodeEventListener} implementation that accumulates event nodes in a
@@ -48,7 +49,7 @@
      */
     public EconomicSetNodeEventListener() {
         this.nodes = EconomicSet.create(Equivalence.IDENTITY);
-        this.filter = EnumSet.allOf(NodeEvent.class);
+        this.filter = EnumSet.of(NodeEvent.INPUT_CHANGED, NodeEvent.NODE_ADDED, NodeEvent.ZERO_USAGES);
     }
 
     /**
@@ -71,12 +72,23 @@
     @Override
     public void changed(NodeEvent e, Node node) {
         if (filter.contains(e)) {
-            nodes.add(node);
+            add(node);
             if (node instanceof IndirectCanonicalization) {
                 for (Node usage : node.usages()) {
-                    nodes.add(usage);
+                    add(usage);
                 }
             }
+
+            if (node instanceof AbstractBeginNode) {
+                AbstractBeginNode abstractBeginNode = (AbstractBeginNode) node;
+                add(abstractBeginNode.predecessor());
+            }
+        }
+    }
+
+    private void add(Node n) {
+        if (n != null) {
+            nodes.add(n);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/TracingNodeEventListener.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.phases.common.util;
+
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Node;
+
+/**
+ * A simple {@link NodeEventListener} implementation that traces events to TTY for debugging
+ * purposes.
+ */
+public class TracingNodeEventListener extends NodeEventListener {
+
+    @Override
+    public void changed(NodeEvent e, Node node) {
+        TTY.println(e.toString() + ": " + node);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java	Fri Jun 28 14:36:42 2019 +0530
@@ -195,10 +195,7 @@
                 return true;
             } else if (phase instanceof PhaseSuite) {
                 PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
-                if (innerSuite.removePhase(phaseClass)) {
-                    if (innerSuite.phases.isEmpty()) {
-                        it.set(newPhase);
-                    }
+                if (innerSuite.replacePhase(phaseClass, newPhase)) {
                     return true;
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -94,7 +94,7 @@
         EARLIEST,
         LATEST,
         LATEST_OUT_OF_LOOPS,
-        FINAL_SCHEDULE;
+        LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS;
 
         public boolean isEarliest() {
             return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER;
@@ -103,6 +103,14 @@
         public boolean isLatest() {
             return !isEarliest();
         }
+
+        public boolean scheduleOutOfLoops() {
+            return this == LATEST_OUT_OF_LOOPS || this == LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS;
+        }
+
+        public boolean considerImplicitNullChecks() {
+            return this == LATEST_OUT_OF_LOOPS_IMPLICIT_NULL_CHECKS;
+        }
     }
 
     private final SchedulingStrategy selectedStrategy;
@@ -228,8 +236,14 @@
                     } else {
                         Block latestBlock = null;
 
+                        if (currentBlock.getFirstDominated() == null && !(currentNode instanceof VirtualState)) {
+                            // This block doesn't dominate any other blocks =>
+                            // node must be scheduled in earliest block.
+                            latestBlock = currentBlock;
+                        }
+
                         LocationIdentity constrainingLocation = null;
-                        if (currentNode instanceof FloatingReadNode) {
+                        if (latestBlock == null && currentNode instanceof FloatingReadNode) {
                             // We are scheduling a floating read node => check memory
                             // anti-dependencies.
                             FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
@@ -544,7 +558,7 @@
 
                 assert latestBlock != null : currentNode;
 
-                if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
+                if (strategy.scheduleOutOfLoops()) {
                     Block currentBlock = latestBlock;
                     while (currentBlock.getLoopDepth() > earliestBlock.getLoopDepth() && currentBlock != earliestBlock.getDominator()) {
                         Block previousCurrentBlock = currentBlock;
@@ -564,27 +578,25 @@
                 }
             }
 
-            if (latestBlock != earliestBlock && currentNode instanceof FloatingReadNode) {
-
-                FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
-                if (isImplicitNullOpportunity(floatingReadNode, earliestBlock) &&
-                                earliestBlock.getRelativeFrequency() < latestBlock.getRelativeFrequency() * IMPLICIT_NULL_CHECK_OPPORTUNITY_PROBABILITY_FACTOR) {
-                    latestBlock = earliestBlock;
-                }
+            if (latestBlock != earliestBlock && strategy.considerImplicitNullChecks() && isImplicitNullOpportunity(currentNode, earliestBlock) &&
+                            earliestBlock.getRelativeFrequency() < latestBlock.getRelativeFrequency() * IMPLICIT_NULL_CHECK_OPPORTUNITY_PROBABILITY_FACTOR) {
+                latestBlock = earliestBlock;
             }
 
             selectLatestBlock(currentNode, earliestBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap);
         }
 
-        private static boolean isImplicitNullOpportunity(FloatingReadNode floatingReadNode, Block block) {
-
-            Node pred = block.getBeginNode().predecessor();
-            if (pred instanceof IfNode) {
-                IfNode ifNode = (IfNode) pred;
-                if (ifNode.condition() instanceof IsNullNode) {
-                    IsNullNode isNullNode = (IsNullNode) ifNode.condition();
-                    if (getUnproxifiedUncompressed(floatingReadNode.getAddress().getBase()) == getUnproxifiedUncompressed(isNullNode.getValue())) {
-                        return true;
+        protected static boolean isImplicitNullOpportunity(Node currentNode, Block block) {
+            if (currentNode instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
+                Node pred = block.getBeginNode().predecessor();
+                if (pred instanceof IfNode) {
+                    IfNode ifNode = (IfNode) pred;
+                    if (ifNode.condition() instanceof IsNullNode && ifNode.getTrueSuccessorProbability() == 0.0) {
+                        IsNullNode isNullNode = (IsNullNode) ifNode.condition();
+                        if (getUnproxifiedUncompressed(floatingReadNode.getAddress().getBase()) == getUnproxifiedUncompressed(isNullNode.getValue())) {
+                            return true;
+                        }
                     }
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/HighTierContext.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/HighTierContext.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,11 +24,12 @@
 
 package org.graalvm.compiler.phases.tiers;
 
+import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.util.Providers;
 
-public class HighTierContext extends PhaseContext {
+public class HighTierContext extends CoreProvidersDelegate {
 
     private final PhaseSuite<HighTierContext> graphBuilderSuite;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/LowTierContext.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/LowTierContext.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,11 +24,12 @@
 
 package org.graalvm.compiler.phases.tiers;
 
+import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate;
 import org.graalvm.compiler.phases.util.Providers;
 
 import jdk.vm.ci.code.TargetDescription;
 
-public class LowTierContext extends PhaseContext {
+public class LowTierContext extends CoreProvidersDelegate {
 
     private final TargetProvider target;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/MidTierContext.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/MidTierContext.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,13 +24,14 @@
 
 package org.graalvm.compiler.phases.tiers;
 
+import org.graalvm.compiler.nodes.spi.CoreProvidersDelegate;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.util.Providers;
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.ProfilingInfo;
 
-public class MidTierContext extends PhaseContext {
+public class MidTierContext extends CoreProvidersDelegate {
 
     private final TargetProvider target;
     private final OptimisticOptimizations optimisticOpts;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.phases.tiers;
-
-import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
-import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
-import org.graalvm.compiler.nodes.spi.CoreProviders;
-import org.graalvm.compiler.nodes.spi.LoweringProvider;
-import org.graalvm.compiler.nodes.spi.Replacements;
-import org.graalvm.compiler.nodes.spi.StampProvider;
-
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-
-public class PhaseContext implements CoreProviders {
-
-    private final CoreProviders providers;
-
-    public PhaseContext(CoreProviders providers) {
-        this.providers = providers;
-    }
-
-    @Override
-    public MetaAccessProvider getMetaAccess() {
-        return providers.getMetaAccess();
-    }
-
-    @Override
-    public ConstantReflectionProvider getConstantReflection() {
-        return providers.getConstantReflection();
-    }
-
-    @Override
-    public ConstantFieldProvider getConstantFieldProvider() {
-        return providers.getConstantFieldProvider();
-    }
-
-    @Override
-    public LoweringProvider getLowerer() {
-        return providers.getLowerer();
-    }
-
-    @Override
-    public Replacements getReplacements() {
-        return providers.getReplacements();
-    }
-
-    @Override
-    public StampProvider getStampProvider() {
-        return providers.getStampProvider();
-    }
-
-    @Override
-    public ForeignCallsProvider getForeignCalls() {
-        return providers.getForeignCalls();
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,11 +27,12 @@
 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.CoreProvidersImpl;
+import org.graalvm.compiler.nodes.spi.GCProvider;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -45,19 +46,19 @@
     private final CodeCacheProvider codeCache;
 
     public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                    ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider) {
-        super(metaAccess, constantReflection, constantFieldProvider, lowerer, replacements, stampProvider, foreignCalls);
+                    ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider, GCProvider gc) {
+        super(metaAccess, constantReflection, constantFieldProvider, lowerer, replacements, stampProvider, foreignCalls, gc);
         this.codeCache = codeCache;
     }
 
     public Providers(Providers copyFrom) {
         this(copyFrom.getMetaAccess(), copyFrom.getCodeCache(), copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), copyFrom.getForeignCalls(), copyFrom.getLowerer(),
-                        copyFrom.getReplacements(), copyFrom.getStampProvider());
+                        copyFrom.getReplacements(), copyFrom.getStampProvider(), copyFrom.getGC());
     }
 
-    public Providers(PhaseContext copyFrom) {
+    public Providers(CoreProviders copyFrom) {
         this(copyFrom.getMetaAccess(), null, copyFrom.getConstantReflection(), copyFrom.getConstantFieldProvider(), null, copyFrom.getLowerer(), copyFrom.getReplacements(),
-                        copyFrom.getStampProvider());
+                        copyFrom.getStampProvider(), copyFrom.getGC());
     }
 
     @Override
@@ -67,41 +68,46 @@
 
     public Providers copyWith(MetaAccessProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
+        return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(CodeCacheProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, substitution, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
+        return new Providers(metaAccess, substitution, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(ConstantReflectionProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
+        return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(ConstantFieldProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(ForeignCallsProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, substitution, lowerer, replacements, stampProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, substitution, lowerer, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(LoweringProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, substitution, replacements, stampProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, substitution, replacements, stampProvider, gc);
     }
 
     public Providers copyWith(Replacements substitution) {
         assert this.getClass() == Providers.class : "must override in " + getClass();
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider, gc);
     }
 
     public Providers copyWith(StampProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
-        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, substitution);
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, substitution, gc);
+    }
+
+    public Providers copyWith(GCProvider substitution) {
+        assert this.getClass() == Providers.class : "must override";
+        return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, substitution);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,9 +31,6 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.JAVA_SPECIFICATION_VERSION;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java11OrEarlier;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool.RoundingMode;
@@ -51,6 +48,7 @@
 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
@@ -166,7 +164,7 @@
     }
 
     private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
-        if (JAVA_SPECIFICATION_VERSION >= 9) {
+        if (JavaVersionUtil.JAVA_SPEC >= 9) {
             Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider);
             r.setAllowOverwrite(true);
             r.registerMethodSubstitution(AArch64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class);
@@ -175,7 +173,7 @@
     }
 
     private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
-        if (JAVA_SPECIFICATION_VERSION >= 9) {
+        if (JavaVersionUtil.JAVA_SPEC >= 9) {
             Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider);
             r.setAllowOverwrite(true);
             r.registerMethodSubstitution(AArch64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class);
@@ -186,10 +184,10 @@
     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class),
                         new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, "Object");
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider),
                             new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object},
-                            Java11OrEarlier ? "Object" : "Reference");
+                            JavaVersionUtil.JAVA_SPEC <= 11 ? "Object" : "Reference");
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOf.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOf.java	Fri Jun 28 14:36:42 2019 +0530
@@ -25,101 +25,100 @@
 package org.graalvm.compiler.replacements.amd64;
 
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.nodes.extended.ForeignCallNode;
-import jdk.internal.vm.compiler.word.Pointer;
-
-import static org.graalvm.compiler.graph.Node.NodeIntrinsic;
 
 public class AMD64ArrayIndexOf {
 
     public static final ForeignCallDescriptor STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES = new ForeignCallDescriptor(
-                    "indexOfTwoConsecutiveBytes", int.class, Pointer.class, int.class, int.class);
+                    "indexOfTwoConsecutiveBytes", int.class, byte[].class, int.class, int.class, int.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS = new ForeignCallDescriptor(
-                    "indexOfTwoConsecutiveChars", int.class, Pointer.class, int.class, int.class);
+                    "indexOfTwoConsecutiveChars", int.class, char[].class, int.class, int.class, int.class);
+    public static final ForeignCallDescriptor STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS_COMPACT = new ForeignCallDescriptor(
+                    "indexOfTwoConsecutiveCharsCompact", int.class, byte[].class, int.class, int.class, int.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_1_BYTE = new ForeignCallDescriptor(
-                    "indexOf1Byte", int.class, Pointer.class, int.class, byte.class);
+                    "indexOf1Byte", int.class, byte[].class, int.class, int.class, byte.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_2_BYTES = new ForeignCallDescriptor(
-                    "indexOf2Bytes", int.class, Pointer.class, int.class, byte.class, byte.class);
+                    "indexOf2Bytes", int.class, byte[].class, int.class, int.class, byte.class, byte.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_3_BYTES = new ForeignCallDescriptor(
-                    "indexOf3Bytes", int.class, Pointer.class, int.class, byte.class, byte.class, byte.class);
+                    "indexOf3Bytes", int.class, byte[].class, int.class, int.class, byte.class, byte.class, byte.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_4_BYTES = new ForeignCallDescriptor(
-                    "indexOf4Bytes", int.class, Pointer.class, int.class, byte.class, byte.class, byte.class, byte.class);
+                    "indexOf4Bytes", int.class, byte[].class, int.class, int.class, byte.class, byte.class, byte.class, byte.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_1_CHAR = new ForeignCallDescriptor(
-                    "indexOf1Char", int.class, Pointer.class, int.class, char.class);
+                    "indexOf1Char", int.class, char[].class, int.class, int.class, char.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_2_CHARS = new ForeignCallDescriptor(
-                    "indexOf2Chars", int.class, Pointer.class, int.class, char.class, char.class);
+                    "indexOf2Chars", int.class, char[].class, int.class, int.class, char.class, char.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_3_CHARS = new ForeignCallDescriptor(
-                    "indexOf3Chars", int.class, Pointer.class, int.class, char.class, char.class, char.class);
+                    "indexOf3Chars", int.class, char[].class, int.class, int.class, char.class, char.class, char.class);
     public static final ForeignCallDescriptor STUB_INDEX_OF_4_CHARS = new ForeignCallDescriptor(
-                    "indexOf4Chars", int.class, Pointer.class, int.class, char.class, char.class, char.class, char.class);
+                    "indexOf4Chars", int.class, char[].class, int.class, int.class, char.class, char.class, char.class, char.class);
+    public static final ForeignCallDescriptor STUB_INDEX_OF_1_CHAR_COMPACT = new ForeignCallDescriptor(
+                    "indexOf1CharCompact", int.class, byte[].class, int.class, int.class, char.class);
+    public static final ForeignCallDescriptor STUB_INDEX_OF_2_CHARS_COMPACT = new ForeignCallDescriptor(
+                    "indexOf2CharsCompact", int.class, byte[].class, int.class, int.class, char.class, char.class);
+    public static final ForeignCallDescriptor STUB_INDEX_OF_3_CHARS_COMPACT = new ForeignCallDescriptor(
+                    "indexOf3CharsCompact", int.class, byte[].class, int.class, int.class, char.class, char.class, char.class);
+    public static final ForeignCallDescriptor STUB_INDEX_OF_4_CHARS_COMPACT = new ForeignCallDescriptor(
+                    "indexOf4CharsCompact", int.class, byte[].class, int.class, int.class, char.class, char.class, char.class, char.class);
 
-    public static int indexOfTwoConsecutiveBytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) {
+    public static int indexOfTwoConsecutiveBytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2) {
         int searchValue = (Byte.toUnsignedInt(b2) << Byte.SIZE) | Byte.toUnsignedInt(b1);
-        return callInt(STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, arrayPointer, arrayLength, searchValue);
+        return AMD64ArrayIndexOfDispatchNode.indexOf2ConsecutiveBytes(STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, array, arrayLength, fromIndex, searchValue);
     }
 
-    public static int indexOfTwoConsecutiveChars(Pointer arrayPointer, int arrayLength, char c1, char c2) {
+    public static int indexOfTwoConsecutiveChars(char[] array, int arrayLength, int fromIndex, char c1, char c2) {
         int searchValue = (c2 << Character.SIZE) | c1;
-        return callInt(STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, arrayPointer, arrayLength, searchValue);
+        return AMD64ArrayIndexOfDispatchNode.indexOf2ConsecutiveChars(STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, array, arrayLength, fromIndex, searchValue);
     }
 
-    public static int indexOf1Byte(Pointer arrayPointer, int arrayLength, byte b) {
-        return callByte1(STUB_INDEX_OF_1_BYTE, arrayPointer, arrayLength, b);
-    }
-
-    public static int indexOf2Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) {
-        return callByte2(STUB_INDEX_OF_2_BYTES, arrayPointer, arrayLength, b1, b2);
-    }
-
-    public static int indexOf3Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3) {
-        return callByte3(STUB_INDEX_OF_3_BYTES, arrayPointer, arrayLength, b1, b2, b3);
+    public static int indexOfTwoConsecutiveChars(byte[] array, int arrayLength, int fromIndex, char c1, char c2) {
+        int searchValue = (c2 << Character.SIZE) | c1;
+        return AMD64ArrayIndexOfDispatchNode.indexOf2ConsecutiveChars(STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS_COMPACT, array, arrayLength, fromIndex, searchValue);
     }
 
-    public static int indexOf4Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3, byte b4) {
-        return callByte4(STUB_INDEX_OF_4_BYTES, arrayPointer, arrayLength, b1, b2, b3, b4);
+    public static int indexOf1Byte(byte[] array, int arrayLength, int fromIndex, byte b) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_1_BYTE, array, arrayLength, fromIndex, b);
     }
 
-    public static int indexOf1Char(Pointer arrayPointer, int arrayLength, char c) {
-        return callChar1(STUB_INDEX_OF_1_CHAR, arrayPointer, arrayLength, c);
+    public static int indexOf2Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_2_BYTES, array, arrayLength, fromIndex, b1, b2);
     }
 
-    public static int indexOf2Chars(Pointer arrayPointer, int arrayLength, char c1, char c2) {
-        return callChar2(STUB_INDEX_OF_2_CHARS, arrayPointer, arrayLength, c1, c2);
+    public static int indexOf3Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2, byte b3) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_3_BYTES, array, arrayLength, fromIndex, b1, b2, b3);
     }
 
-    public static int indexOf3Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3) {
-        return callChar3(STUB_INDEX_OF_3_CHARS, arrayPointer, arrayLength, c1, c2, c3);
+    public static int indexOf4Bytes(byte[] array, int arrayLength, int fromIndex, byte b1, byte b2, byte b3, byte b4) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_4_BYTES, array, arrayLength, fromIndex, b1, b2, b3, b4);
     }
 
-    public static int indexOf4Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4) {
-        return callChar4(STUB_INDEX_OF_4_CHARS, arrayPointer, arrayLength, c1, c2, c3, c4);
+    public static int indexOf1Char(char[] array, int arrayLength, int fromIndex, char c) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_1_CHAR, array, arrayLength, fromIndex, c);
+    }
+
+    public static int indexOf2Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_2_CHARS, array, arrayLength, fromIndex, c1, c2);
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callInt(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, int v1);
-
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callByte1(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1);
+    public static int indexOf3Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2, char c3) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_3_CHARS, array, arrayLength, fromIndex, c1, c2, c3);
+    }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callByte2(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2);
+    public static int indexOf4Chars(char[] array, int arrayLength, int fromIndex, char c1, char c2, char c3, char c4) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_4_CHARS, array, arrayLength, fromIndex, c1, c2, c3, c4);
+    }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callByte3(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2, byte v3);
+    public static int indexOf1Char(byte[] array, int arrayLength, int fromIndex, char c) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_1_CHAR_COMPACT, array, arrayLength, fromIndex, c);
+    }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callByte4(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2, byte v3, byte v4);
-
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callChar1(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1);
+    public static int indexOf2Chars(byte[] array, int arrayLength, int fromIndex, char c1, char c2) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_2_CHARS_COMPACT, array, arrayLength, fromIndex, c1, c2);
+    }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callChar2(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2);
+    public static int indexOf3Chars(byte[] array, int arrayLength, int fromIndex, char c1, char c2, char c3) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_3_CHARS_COMPACT, array, arrayLength, fromIndex, c1, c2, c3);
+    }
 
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callChar3(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2, char v3);
-
-    @NodeIntrinsic(value = ForeignCallNode.class)
-    private static native int callChar4(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2, char v3, char v4);
+    public static int indexOf4Chars(byte[] array, int arrayLength, int fromIndex, char c1, char c2, char c3, char c4) {
+        return AMD64ArrayIndexOfDispatchNode.indexOf(STUB_INDEX_OF_4_CHARS_COMPACT, array, arrayLength, fromIndex, c1, c2, c3, c4);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfDispatchNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.replacements.amd64;
+
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.DeoptimizingNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * This node is a placeholder for all variants of intrinsified indexof-operations. It may be lowered
+ * to a {@link AMD64ArrayIndexOfNode} or a specialized snippet.
+ */
+@NodeInfo(size = SIZE_512, cycles = NodeCycles.CYCLES_UNKNOWN)
+public class AMD64ArrayIndexOfDispatchNode extends FixedWithNextNode implements Lowerable, MemoryAccess, DeoptimizingNode.DeoptBefore {
+
+    public static final NodeClass<AMD64ArrayIndexOfDispatchNode> TYPE = NodeClass.create(AMD64ArrayIndexOfDispatchNode.class);
+
+    private final ForeignCallDescriptor stubCallDescriptor;
+    private final JavaKind arrayKind;
+    private final JavaKind valueKind;
+    private final boolean findTwoConsecutive;
+
+    @Input private ValueNode arrayPointer;
+    @Input private ValueNode arrayLength;
+    @Input private ValueNode fromIndex;
+    @Input private NodeInputList<ValueNode> searchValues;
+
+    @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
+    @OptionalInput(InputType.State) protected FrameState stateBefore;
+
+    public AMD64ArrayIndexOfDispatchNode(@ConstantNodeParameter ForeignCallDescriptor stubCallDescriptor, @ConstantNodeParameter JavaKind arrayKind, @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive, ValueNode arrayPointer, ValueNode arrayLength, ValueNode fromIndex, ValueNode... searchValues) {
+        super(TYPE, StampFactory.forKind(JavaKind.Int));
+        this.stubCallDescriptor = stubCallDescriptor;
+        this.arrayKind = arrayKind;
+        this.valueKind = valueKind;
+        this.findTwoConsecutive = findTwoConsecutive;
+        this.arrayPointer = arrayPointer;
+        this.arrayLength = arrayLength;
+        this.fromIndex = fromIndex;
+        this.searchValues = new NodeInputList<>(this, searchValues);
+    }
+
+    public boolean isFindTwoConsecutive() {
+        return findTwoConsecutive;
+    }
+
+    public ValueNode getArrayPointer() {
+        return arrayPointer;
+    }
+
+    public ValueNode getArrayLength() {
+        return arrayLength;
+    }
+
+    public ValueNode getFromIndex() {
+        return fromIndex;
+    }
+
+    public NodeInputList<ValueNode> getSearchValues() {
+        return searchValues;
+    }
+
+    @Override
+    public boolean canDeoptimize() {
+        return true;
+    }
+
+    @Override
+    public void setStateBefore(FrameState f) {
+        updateUsages(stateBefore, f);
+        stateBefore = f;
+    }
+
+    @Override
+    public FrameState stateBefore() {
+        return stateBefore;
+    }
+
+    public ForeignCallDescriptor getStubCallDescriptor() {
+        return stubCallDescriptor;
+    }
+
+    public int getNumberOfValues() {
+        return searchValues.size();
+    }
+
+    public JavaKind getArrayKind() {
+        return arrayKind;
+    }
+
+    public JavaKind getValueKind() {
+        return valueKind;
+    }
+
+    public JavaKind getComparisonKind() {
+        return findTwoConsecutive ? (valueKind == JavaKind.Byte ? JavaKind.Char : JavaKind.Int) : valueKind;
+    }
+
+    public ValueNode[] getStubCallArgs() {
+        ValueNode[] ret = new ValueNode[searchValues.size() + 3];
+        ret[0] = arrayPointer;
+        ret[1] = arrayLength;
+        ret[2] = fromIndex;
+        for (int i = 0; i < searchValues.size(); i++) {
+            ret[3 + i] = searchValues.get(i);
+        }
+        return ret;
+    }
+
+    public AMD64ArrayIndexOfDispatchNode(@ConstantNodeParameter ForeignCallDescriptor stubCallDescriptor, @ConstantNodeParameter JavaKind arrayKind, @ConstantNodeParameter JavaKind valueKind,
+                    ValueNode arrayPointer, ValueNode arrayLength, ValueNode fromIndex, ValueNode... searchValues) {
+        this(stubCallDescriptor, arrayKind, valueKind, false, arrayPointer, arrayLength, fromIndex, searchValues);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return NamedLocationIdentity.getArrayLocation(arrayKind);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
+        lastLocationAccess = lla;
+    }
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3, byte v4);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2, char v3);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter ForeignCallDescriptor descriptor,
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, int searchValue);
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, byte v1) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, byte v1, byte v2) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3, byte v4) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, char v1) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, char v1, char v2) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, char v1, char v2, char v3) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, char[] array, int arrayLength, int fromIndex, char v1) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, char[] array, int arrayLength, int fromIndex, char v1, char v2) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, char[] array, int arrayLength, int fromIndex, char v1, char v2, char v3) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(@ConstantNodeParameter ForeignCallDescriptor descriptor, char[] array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
+
+    public static int indexOf2ConsecutiveBytes(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Byte, true, array, arrayLength, fromIndex, values);
+    }
+
+    public static int indexOf2ConsecutiveChars(@ConstantNodeParameter ForeignCallDescriptor descriptor, byte[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Byte, JavaKind.Char, true, array, arrayLength, fromIndex, values);
+    }
+
+    public static int indexOf2ConsecutiveChars(@ConstantNodeParameter ForeignCallDescriptor descriptor, char[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(descriptor, JavaKind.Char, JavaKind.Char, true, array, arrayLength, fromIndex, values);
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,8 +24,8 @@
 
 package org.graalvm.compiler.replacements.amd64;
 
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Value;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512;
+
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
@@ -41,41 +41,46 @@
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import jdk.internal.vm.compiler.word.LocationIdentity;
-import jdk.internal.vm.compiler.word.Pointer;
 
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
 
 @NodeInfo(size = SIZE_512, cycles = NodeCycles.CYCLES_UNKNOWN)
 public class AMD64ArrayIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess {
 
     public static final NodeClass<AMD64ArrayIndexOfNode> TYPE = NodeClass.create(AMD64ArrayIndexOfNode.class);
 
-    private final JavaKind kind;
+    private final JavaKind arrayKind;
+    private final JavaKind valueKind;
     private final boolean findTwoConsecutive;
 
     @Input private ValueNode arrayPointer;
     @Input private ValueNode arrayLength;
+    @Input private ValueNode fromIndex;
     @Input private NodeInputList<ValueNode> searchValues;
 
     @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
 
-    public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind kind, @ConstantNodeParameter boolean findTwoConsecutive,
-                    ValueNode arrayPointer, ValueNode arrayLength, ValueNode... searchValues) {
+    public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind arrayKind, @ConstantNodeParameter JavaKind valueKind, @ConstantNodeParameter boolean findTwoConsecutive,
+                    ValueNode arrayPointer, ValueNode arrayLength, ValueNode fromIndex, ValueNode... searchValues) {
         super(TYPE, StampFactory.forKind(JavaKind.Int));
-        this.kind = kind;
+        this.arrayKind = arrayKind;
+        this.valueKind = valueKind;
         this.findTwoConsecutive = findTwoConsecutive;
         this.arrayPointer = arrayPointer;
         this.arrayLength = arrayLength;
+        this.fromIndex = fromIndex;
         this.searchValues = new NodeInputList<>(this, searchValues);
     }
 
-    public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind kind, ValueNode arrayPointer, ValueNode arrayLength, ValueNode... searchValues) {
-        this(kind, false, arrayPointer, arrayLength, searchValues);
+    public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind arrayKind, @ConstantNodeParameter JavaKind valueKind,
+                    ValueNode arrayPointer, ValueNode arrayLength, ValueNode fromIndex, ValueNode... searchValues) {
+        this(arrayKind, valueKind, false, arrayPointer, arrayLength, fromIndex, searchValues);
     }
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return NamedLocationIdentity.getArrayLocation(kind);
+        return NamedLocationIdentity.getArrayLocation(arrayKind);
     }
 
     @Override
@@ -84,7 +89,8 @@
         for (int i = 0; i < searchValues.size(); i++) {
             searchValueOperands[i] = gen.operand(searchValues.get(i));
         }
-        Value result = gen.getLIRGeneratorTool().emitArrayIndexOf(kind, findTwoConsecutive, gen.operand(arrayPointer), gen.operand(arrayLength), searchValueOperands);
+        Value result = gen.getLIRGeneratorTool().emitArrayIndexOf(arrayKind, valueKind, findTwoConsecutive,
+                        gen.operand(arrayPointer), gen.operand(arrayLength), gen.operand(fromIndex), searchValueOperands);
         gen.setResult(this, result);
     }
 
@@ -100,30 +106,125 @@
     }
 
     @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, @ConstantNodeParameter boolean findTwoConsecutive,
-                    Pointer arrayPointer, int arrayLength, int searchValue);
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3);
 
     @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1);
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3, byte v4);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1);
 
     @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2);
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2);
 
     @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2, char c3);
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2, char v3);
+
+    @NodeIntrinsic
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4);
 
     @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4);
+    private static native int optimizedArrayIndexOf(
+                    @ConstantNodeParameter JavaKind arrayKind,
+                    @ConstantNodeParameter JavaKind valueKind,
+                    @ConstantNodeParameter boolean findTwoConsecutive,
+                    Object array, int arrayLength, int fromIndex, int searchValue);
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, byte v1) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, byte v1, byte v2) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2);
+    }
 
-    @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1);
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, byte v1, byte v2, byte v3, byte v4) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Byte, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, char v1) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, char v1, char v2) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2);
+    }
 
-    @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2);
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, char v1, char v2, char v3) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(byte[] array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
+
+    public static int indexOf(char[] array, int arrayLength, int fromIndex, char v1) {
+        return optimizedArrayIndexOf(JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1);
+    }
+
+    public static int indexOf(char[] array, int arrayLength, int fromIndex, char v1, char v2) {
+        return optimizedArrayIndexOf(JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2);
+    }
 
-    @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2, byte c3);
+    public static int indexOf(char[] array, int arrayLength, int fromIndex, char v1, char v2, char v3) {
+        return optimizedArrayIndexOf(JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3);
+    }
+
+    public static int indexOf(char[] array, int arrayLength, int fromIndex, char v1, char v2, char v3, char v4) {
+        return optimizedArrayIndexOf(JavaKind.Char, JavaKind.Char, false, array, arrayLength, fromIndex, v1, v2, v3, v4);
+    }
 
-    @NodeIntrinsic
-    public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2, byte c3, byte c4);
+    public static int indexOf2ConsecutiveBytes(byte[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Byte, true, array, arrayLength, fromIndex, values);
+    }
+
+    public static int indexOf2ConsecutiveChars(byte[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(JavaKind.Byte, JavaKind.Char, true, array, arrayLength, fromIndex, values);
+    }
+
+    public static int indexOf2ConsecutiveChars(char[] array, int arrayLength, int fromIndex, int values) {
+        return optimizedArrayIndexOf(JavaKind.Char, JavaKind.Char, true, array, arrayLength, fromIndex, values);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,8 +32,6 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java11OrEarlier;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import java.util.Arrays;
 
@@ -62,6 +60,7 @@
 import org.graalvm.compiler.replacements.nodes.FusedMultiplyAddNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64.CPUFeature;
@@ -95,7 +94,7 @@
     }
 
     private static void registerThreadPlugins(InvocationPlugins plugins, AMD64 arch) {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             // Pause instruction introduced with SSE2
             if (arch.getFeatures().contains(AMD64.CPUFeature.SSE2)) {
                 Registration r = new Registration(plugins, Thread.class);
@@ -177,7 +176,7 @@
             registerRound(r, "floor", RoundingMode.DOWN);
         }
 
-        if (useFMAIntrinsics && !Java8OrEarlier && arch.getFeatures().contains(CPUFeature.FMA)) {
+        if (useFMAIntrinsics && JavaVersionUtil.JAVA_SPEC > 8 && arch.getFeatures().contains(CPUFeature.FMA)) {
             registerFMA(r);
         }
     }
@@ -248,7 +247,7 @@
     }
 
     private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             Registration r;
             r = new Registration(plugins, String.class, replacementsBytecodeProvider);
             r.setAllowOverwrite(true);
@@ -284,9 +283,10 @@
 
     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider, boolean explicitUnsafeNullChecks) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class), explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true);
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider), explicitUnsafeNullChecks,
-                            new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object}, Java11OrEarlier);
+                            new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object},
+                            JavaVersionUtil.JAVA_SPEC <= 11);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -112,12 +112,7 @@
             // Note: fromIndex might be near -1>>>1.
             return -1;
         }
-        Pointer sourcePointer = byteOffsetPointer(value, fromIndex);
-        int result = AMD64ArrayIndexOf.indexOf1Byte(sourcePointer, length - fromIndex, (byte) ch);
-        if (result != -1) {
-            return result + fromIndex;
-        }
-        return result;
+        return AMD64ArrayIndexOf.indexOf1Byte(value, length, fromIndex, (byte) ch);
     }
 
     @MethodSubstitution
@@ -137,37 +132,25 @@
             // The empty string contains nothing except the empty string.
             return -1;
         }
-        int totalOffset = fromIndex;
         if (targetCount == 1) {
-            Pointer sourcePointer = byteOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOf1Byte(sourcePointer, sourceCount - fromIndex, target[0]);
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOf1Byte(source, sourceCount, fromIndex, target[0]);
         } else if (targetCount == 2) {
-            Pointer sourcePointer = byteOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveBytes(sourcePointer, sourceCount - fromIndex, target[0], target[1]);
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOfTwoConsecutiveBytes(source, sourceCount, fromIndex, target[0], target[1]);
         } else {
-            int haystackLength = sourceCount - (fromIndex + (targetCount - 2));
-            while (haystackLength > 0) {
-                Pointer sourcePointer = byteOffsetPointer(source, totalOffset);
-                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveBytes(sourcePointer, haystackLength, target[0], target[1]);
+            int haystackLength = sourceCount - (targetCount - 2);
+            int offset = fromIndex;
+            while (offset < haystackLength) {
+                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveBytes(source, haystackLength, offset, target[0], target[1]);
                 if (indexOfResult < 0) {
                     return -1;
                 }
-                totalOffset += indexOfResult;
-                haystackLength -= (indexOfResult + 1);
-                Pointer cmpSourcePointer = byteOffsetPointer(source, totalOffset);
+                offset = indexOfResult;
+                Pointer cmpSourcePointer = byteOffsetPointer(source, offset);
                 Pointer targetPointer = pointer(target);
                 if (ArrayRegionEqualsNode.regionEquals(cmpSourcePointer, targetPointer, targetCount, JavaKind.Byte)) {
-                    return totalOffset;
+                    return offset;
                 }
-                totalOffset++;
+                offset++;
             }
             return -1;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -84,29 +84,17 @@
         }
 
         if (targetCount == 1) {
-            Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED));
-            int indexOfResult = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, target[targetOffset]);
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOf1Char(source, sourceCount, totalOffset, target[targetOffset]);
         } else if (targetCount == 2) {
-            Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED));
-            int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, sourceCount - fromIndex, target[targetOffset], target[targetOffset + 1]);
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, sourceCount, totalOffset, target[targetOffset], target[targetOffset + 1]);
         } else {
-            int haystackLength = sourceCount - (fromIndex + (targetCount - 2));
-            while (haystackLength > 0) {
-                Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED));
-                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, haystackLength, target[targetOffset], target[targetOffset + 1]);
+            int haystackLength = sourceCount - (targetCount - 2);
+            while (totalOffset < haystackLength) {
+                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, haystackLength, totalOffset, target[targetOffset], target[targetOffset + 1]);
                 if (indexOfResult < 0) {
                     return -1;
                 }
-                totalOffset += indexOfResult;
-                haystackLength -= (indexOfResult + 1);
+                totalOffset = indexOfResult;
                 Pointer cmpSourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED));
                 Pointer targetPointer = Word.objectToTrackedPointer(target).add(charArrayBaseOffset(INJECTED)).add(targetOffset * charArrayIndexScale(INJECTED));
                 if (ArrayRegionEqualsNode.regionEquals(cmpSourcePointer, targetPointer, targetCount, JavaKind.Char)) {
@@ -133,13 +121,7 @@
 
         if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
             char[] sourceArray = StringSubstitutions.getValue(source);
-
-            Pointer sourcePointer = Word.objectToTrackedPointer(sourceArray).add(charArrayBaseOffset(INJECTED)).add(fromIndex * charArrayIndexScale(INJECTED));
-            int result = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, (char) ch);
-            if (result != -1) {
-                return result + fromIndex;
-            }
-            return result;
+            return AMD64ArrayIndexOf.indexOf1Char(sourceArray, sourceCount, fromIndex, (char) ch);
         } else {
             return indexOf(source, ch, origFromIndex);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java	Fri Jun 28 14:36:42 2019 +0530
@@ -103,12 +103,7 @@
 
     @MethodSubstitution
     public static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) {
-        Pointer sourcePointer = charOffsetPointer(value, fromIndex);
-        int result = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, max - fromIndex, (char) ch);
-        if (result != -1) {
-            return result + fromIndex;
-        }
-        return result;
+        return AMD64ArrayIndexOf.indexOf1Char(value, max, fromIndex, (char) ch);
     }
 
     private static Word pointer(byte[] target) {
@@ -125,39 +120,26 @@
         ReplacementsUtil.runtimeAssert(targetCount > 0, "StringUTF16.indexOfUnsafe invalid args: targetCount <= 0");
         ReplacementsUtil.runtimeAssert(targetCount <= length(target), "StringUTF16.indexOfUnsafe invalid args: targetCount > length(target)");
         ReplacementsUtil.runtimeAssert(sourceCount >= targetCount, "StringUTF16.indexOfUnsafe invalid args: sourceCount < targetCount");
-        int totalOffset = fromIndex;
         if (targetCount == 1) {
-            Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, StringUTF16Substitutions.getChar(target, 0));
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOf1Char(source, sourceCount, fromIndex, StringUTF16Substitutions.getChar(target, 0));
         } else if (targetCount == 2) {
-            Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, sourceCount - fromIndex, StringUTF16Substitutions.getChar(target, 0),
-                            StringUTF16Substitutions.getChar(target, 1));
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, sourceCount, fromIndex, StringUTF16Substitutions.getChar(target, 0), StringUTF16Substitutions.getChar(target, 1));
         } else {
-            int haystackLength = sourceCount - (fromIndex + (targetCount - 2));
-            while (haystackLength > 0) {
-                Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, haystackLength, StringUTF16Substitutions.getChar(target, 0),
+            int haystackLength = sourceCount - (targetCount - 2);
+            int offset = fromIndex;
+            while (offset < haystackLength) {
+                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, haystackLength, offset, StringUTF16Substitutions.getChar(target, 0),
                                 StringUTF16Substitutions.getChar(target, 1));
                 if (indexOfResult < 0) {
                     return -1;
                 }
-                totalOffset += indexOfResult;
-                haystackLength -= (indexOfResult + 1);
-                Pointer cmpSourcePointer = charOffsetPointer(source, totalOffset);
+                offset = indexOfResult;
+                Pointer cmpSourcePointer = charOffsetPointer(source, offset);
                 Pointer targetPointer = pointer(target);
                 if (ArrayRegionEqualsNode.regionEquals(cmpSourcePointer, targetPointer, targetCount, JavaKind.Char)) {
-                    return totalOffset;
+                    return offset;
                 }
-                totalOffset++;
+                offset++;
             }
             return -1;
         }
@@ -169,37 +151,25 @@
         ReplacementsUtil.runtimeAssert(targetCount > 0, "StringUTF16.indexOfLatin1Unsafe invalid args: targetCount <= 0");
         ReplacementsUtil.runtimeAssert(targetCount <= target.length, "StringUTF16.indexOfLatin1Unsafe invalid args: targetCount > length(target)");
         ReplacementsUtil.runtimeAssert(sourceCount >= targetCount, "StringUTF16.indexOfLatin1Unsafe invalid args: sourceCount < targetCount");
-        int totalOffset = fromIndex;
         if (targetCount == 1) {
-            Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, (char) Byte.toUnsignedInt(target[0]));
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOf1Char(source, sourceCount, fromIndex, (char) Byte.toUnsignedInt(target[0]));
         } else if (targetCount == 2) {
-            Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-            int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, sourceCount - fromIndex, (char) Byte.toUnsignedInt(target[0]), (char) Byte.toUnsignedInt(target[1]));
-            if (indexOfResult >= 0) {
-                return indexOfResult + totalOffset;
-            }
-            return indexOfResult;
+            return AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, sourceCount, fromIndex, (char) Byte.toUnsignedInt(target[0]), (char) Byte.toUnsignedInt(target[1]));
         } else {
-            int haystackLength = sourceCount - (fromIndex + (targetCount - 2));
-            while (haystackLength > 0) {
-                Pointer sourcePointer = charOffsetPointer(source, totalOffset);
-                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, haystackLength, (char) Byte.toUnsignedInt(target[0]), (char) Byte.toUnsignedInt(target[1]));
+            int haystackLength = sourceCount - (targetCount - 2);
+            int offset = fromIndex;
+            while (offset < haystackLength) {
+                int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(source, haystackLength, offset, (char) Byte.toUnsignedInt(target[0]), (char) Byte.toUnsignedInt(target[1]));
                 if (indexOfResult < 0) {
                     return -1;
                 }
-                totalOffset += indexOfResult;
-                haystackLength -= (indexOfResult + 1);
-                Pointer cmpSourcePointer = charOffsetPointer(source, totalOffset);
+                offset = indexOfResult;
+                Pointer cmpSourcePointer = charOffsetPointer(source, offset);
                 Pointer targetPointer = pointer(target);
                 if (ArrayRegionEqualsNode.regionEquals(cmpSourcePointer, targetPointer, targetCount, JavaKind.Char, JavaKind.Byte)) {
-                    return totalOffset;
+                    return offset;
                 }
-                totalOffset++;
+                offset++;
             }
             return -1;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,7 +33,6 @@
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Assert;
@@ -133,7 +132,7 @@
         StructuredGraph graph = parseEager("testCanonicalLengthSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
@@ -149,7 +148,7 @@
         StructuredGraph graph = parseEager("testCanonicalEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
@@ -163,9 +162,9 @@
         StructuredGraph graph = parseEager("testVirtualEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
@@ -181,9 +180,9 @@
         StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
         new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,6 +34,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.AbstractInliningPhase;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.ExportingClassLoader;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -103,7 +104,7 @@
 
     @Test
     public void test3() {
-        Assume.assumeTrue("Only works on jdk8 right now", Java8OrEarlier);
+        Assume.assumeTrue("Only works on jdk8 right now", JavaVersionUtil.JAVA_SPEC <= 8);
         ResolvedJavaMethod method = getResolvedJavaMethod("test3Snippet");
 
         for (int i = 0; i < 2; i++) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -266,8 +266,8 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified";
-        return super.checkHighTierGraph(graph);
+        super.checkHighTierGraph(graph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -94,14 +94,13 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         // check that folding happened correctly
         StartNode start = graph.start();
         assert start.next() instanceof ReturnNode : "expected ReturnNode, got " + start.next();
 
         ReturnNode ret = (ReturnNode) start.next();
         assert ret.result().isConstant() : "expected ConstantNode, got " + ret.result();
-        return true;
     }
 
     @Test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InvokerSignatureMismatchTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.replacements.test;
+
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import org.junit.Test;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+
+import org.graalvm.compiler.core.test.CustomizedBytecodePatternTest;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class InvokerSignatureMismatchTest {
+
+    @Test
+    public void test() throws Throwable {
+        List<String> args = withoutDebuggerArguments(getVMCommandLine());
+        String classPath = System.getProperty("java.class.path");
+        classPath = classPath + File.pathSeparator + TestISMBL.class.getProtectionDomain().getCodeSource().getLocation().getPath();
+        args.add("-Xbootclasspath/a:" + classPath);
+        args.add("-XX:-TieredCompilation");
+        args.add("-XX:+EnableJVMCI");
+        args.add("-XX:+UseJVMCICompiler");
+
+        args.add(TestISMBL.class.getName());
+        Subprocess proc = SubprocessUtil.java(args);
+        if (proc.exitCode != 0) {
+            System.out.println(proc);
+        }
+    }
+}
+
+class TestISMBL extends CustomizedBytecodePatternTest {
+
+    public static void main(String[] args) {
+        try {
+            new TestISMBL().test();
+        } catch (Throwable e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+        System.exit(0);
+    }
+
+    private void test() throws Throwable {
+        getClass("java/lang/invoke/MHHelper");
+        Class<?> testClass = getClass("ISMTest");
+
+        ResolvedJavaMethod mL = getResolvedJavaMethod(testClass, "mainLink");
+        ResolvedJavaMethod mI = getResolvedJavaMethod(testClass, "mainInvoke");
+        executeActual(mL, null, 100);
+        executeActual(mI, null, 100);
+    }
+
+    @Override
+    protected Class<?> getClass(String className) throws ClassNotFoundException {
+        if (className.equals("java/lang/invoke/MHHelper")) {
+            return super.getClassBL(className, MethodHandles.lookup());
+        } else {
+            return super.getClass(className);
+        }
+    }
+
+    @Override
+    protected byte[] generateClass(String className) {
+        String[] exceptions = new String[]{"java/lang/Throwable"};
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+        cw.visit(52, ACC_SUPER | ACC_PUBLIC, className, null, "java/lang/Object", null);
+
+        if (className.equals("java/lang/invoke/MHHelper")) {
+            MethodVisitor internalMemberName = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", null, exceptions);
+            internalMemberName.visitCode();
+            internalMemberName.visitVarInsn(ALOAD, 0);
+            internalMemberName.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "internalMemberName", "()Ljava/lang/invoke/MemberName;", false);
+            internalMemberName.visitInsn(ARETURN);
+            internalMemberName.visitMaxs(1, 1);
+            internalMemberName.visitEnd();
+
+            MethodVisitor linkToStatic = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "linkToStatic", "(FLjava/lang/Object;)I", null, exceptions);
+            linkToStatic.visitCode();
+            linkToStatic.visitVarInsn(FLOAD, 0);
+            linkToStatic.visitVarInsn(ALOAD, 1);
+            linkToStatic.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandle", "linkToStatic", "(FLjava/lang/Object;)I", false);
+            linkToStatic.visitInsn(IRETURN);
+            linkToStatic.visitMaxs(1, 1);
+            linkToStatic.visitEnd();
+
+            MethodVisitor invokeBasicI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", null, exceptions);
+            invokeBasicI.visitCode();
+            invokeBasicI.visitVarInsn(ALOAD, 0);
+            invokeBasicI.visitVarInsn(FLOAD, 1);
+            invokeBasicI.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeBasic", "(F)I", false);
+            invokeBasicI.visitInsn(IRETURN);
+            invokeBasicI.visitMaxs(1, 1);
+            invokeBasicI.visitEnd();
+
+        } else {
+            assert className.equals("ISMTest") : className;
+            cw.visitField(ACC_FINAL | ACC_STATIC, "INT_MH", "Ljava/lang/invoke/MethodHandle;", null, null).visitAnnotation("Ljava/lang/invoke/Stable.class;", true).visitEnd();
+            MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, exceptions);
+            clinit.visitCode();
+            clinit.visitInsn(ACONST_NULL);
+            clinit.visitVarInsn(ASTORE, 0);
+            clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
+            clinit.visitLdcInsn(Type.getObjectType(className));
+            clinit.visitLdcInsn("bodyI");
+            clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
+            clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
+            clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "methodType", "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;", false);
+            clinit.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic",
+                            "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false);
+            clinit.visitFieldInsn(PUTSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
+            clinit.visitInsn(RETURN);
+            clinit.visitMaxs(1, 1);
+            clinit.visitEnd();
+
+            MethodVisitor mainLink = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainLink", "(I)I", null, exceptions);
+            mainLink.visitCode();
+            mainLink.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
+            mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MHHelper", "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", false);
+            mainLink.visitVarInsn(ASTORE, 1);
+            mainLink.visitVarInsn(ILOAD, 0);
+            mainLink.visitInsn(I2F);
+            mainLink.visitVarInsn(ALOAD, 1);
+            mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MHHelper", "linkToStatic", "(FLjava/lang/Object;)I", false);
+            mainLink.visitInsn(IRETURN);
+            mainLink.visitMaxs(1, 1);
+            mainLink.visitEnd();
+
+            MethodVisitor mainInvoke = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainInvoke", "(I)I", null, exceptions);
+            mainInvoke.visitCode();
+            mainInvoke.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
+            mainInvoke.visitVarInsn(ILOAD, 0);
+            mainInvoke.visitInsn(I2F);
+            mainInvoke.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MHHelper", "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", false);
+            mainInvoke.visitInsn(IRETURN);
+            mainInvoke.visitMaxs(1, 1);
+            mainInvoke.visitEnd();
+
+            MethodVisitor bodyI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "bodyI", "(I)I", null, null);
+            bodyI.visitCode();
+            bodyI.visitVarInsn(ILOAD, 0);
+            bodyI.visitIntInsn(SIPUSH, 1023);
+            bodyI.visitInsn(IAND);
+            bodyI.visitInsn(IRETURN);
+            bodyI.visitMaxs(1, 1);
+            bodyI.visitEnd();
+        }
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,9 +43,9 @@
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.replacements.CachingPEGraphDecoder;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import org.junit.Test;
@@ -138,13 +138,13 @@
             registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
             targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build();
             CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES,
-                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null);
+                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null, null);
 
             decoder.decode(testMethod, false, false);
             debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph");
             targetGraph.verify();
 
-            PhaseContext context = new PhaseContext(getProviders());
+            CoreProviders context = getProviders();
             new CanonicalizerPhase().apply(targetGraph, context);
             targetGraph.verify();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -69,7 +69,7 @@
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.test.GraalTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -375,7 +375,7 @@
 
     @Test
     public void testNextAfter() {
-        Assume.assumeFalse(GraalTest.Java8OrEarlier);
+        Assume.assumeFalse(JavaVersionUtil.JAVA_SPEC <= 8);
         double[] inArray = new double[1024];
         double[] outArray = new double[1024];
         for (int i = 0; i < inArray.length; i++) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -34,6 +34,7 @@
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -51,7 +52,7 @@
 
 /**
  * Exercise
- * {@link org.graalvm.compiler.nodes.spi.Replacements#getIntrinsicGraph(ResolvedJavaMethod, CompilationIdentifier, DebugContext)}
+ * {@link org.graalvm.compiler.nodes.spi.Replacements#getIntrinsicGraph(ResolvedJavaMethod, CompilationIdentifier, DebugContext, Cancellable)}
  * with regular method substitutions and encoded graphs.
  */
 @RunWith(Parameterized.class)
@@ -113,14 +114,14 @@
     private StructuredGraph getIntrinsicGraph(boolean useEncodedGraphs) {
         OptionValues options = new OptionValues(getDebugContext().getOptions(), GraalOptions.UseEncodedGraphs, useEncodedGraphs);
         DebugContext debugContext = DebugContext.create(options, getDebugContext().getDescription(), getDebugHandlersFactories());
-        return getReplacements().getIntrinsicGraph(method, CompilationIdentifier.INVALID_COMPILATION_ID, debugContext);
+        return getReplacements().getIntrinsicGraph(method, CompilationIdentifier.INVALID_COMPILATION_ID, debugContext, null);
     }
 
     StructuredGraph expectedGraph;
     StructuredGraph actualGraph;
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         // Capture the graphs after high tier
         if (expectedGraph == null) {
             expectedGraph = (StructuredGraph) graph.copy(graph.getDebug());
@@ -128,7 +129,7 @@
             assert actualGraph == null;
             actualGraph = (StructuredGraph) graph.copy(graph.getDebug());
         }
-        return super.checkHighTierGraph(graph);
+        super.checkHighTierGraph(graph);
     }
 
     @Test
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -91,7 +91,7 @@
         OptionValues options;
         boolean needCheckNode = true;
 
-        if (JavaVersionUtil.Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             needCheckNode = false;
         } else {
             List<String> vmArgs = GraalServices.getInputArguments();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.replacements.amd64.AMD64StringLatin1Substitutions;
 import org.graalvm.compiler.replacements.amd64.AMD64StringUTF16CompressNode;
 import org.graalvm.compiler.replacements.amd64.AMD64StringUTF16Substitutions;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.AddExports;
 import org.junit.Before;
 import org.junit.Test;
@@ -55,7 +56,7 @@
 
     @Before
     public void checkAMD64() {
-        assumeFalse(Java8OrEarlier);
+        assumeFalse(JavaVersionUtil.JAVA_SPEC <= 8);
         // Test case is (currently) AMD64 only.
         assumeTrue(getTarget().arch instanceof AMD64);
     }
@@ -114,7 +115,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringLatin1");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "inflate", byte[].class, int.class, byte[].class, int.class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, AMD64StringLatin1InflateNode.class);
 
         InstalledCode code = getCode(caller, graph);
@@ -152,7 +153,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringLatin1");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "inflate", byte[].class, int.class, char[].class, int.class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, AMD64StringLatin1InflateNode.class);
 
         InstalledCode code = getCode(caller, graph);
@@ -217,7 +218,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringUTF16");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "compress", byte[].class, int.class, byte[].class, int.class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, AMD64StringUTF16CompressNode.class);
 
         InstalledCode code = getCode(caller, graph);
@@ -253,7 +254,7 @@
         Class<?> javaclass = Class.forName("java.lang.StringUTF16");
 
         ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "compress", char[].class, int.class, byte[].class, int.class, int.class);
-        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+        StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
         assertInGraph(graph, AMD64StringUTF16CompressNode.class);
 
         InstalledCode code = getCode(caller, graph);
@@ -299,7 +300,7 @@
         TestMethods(String testmname, Class<?> javaclass, Class<?> intrinsicClass, String javamname, Class<?>... params) {
             javamethod = getResolvedJavaMethod(javaclass, javamname, params);
             testmethod = getResolvedJavaMethod(testmname);
-            testgraph = getReplacements().getIntrinsicGraph(javamethod, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
+            testgraph = getReplacements().getIntrinsicGraph(javamethod, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext(), null);
             assertInGraph(testgraph, intrinsicClass);
 
             assert javamethod != null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -27,6 +27,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.replacements.StringSubstitutions;
 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.junit.Test;
 
 import jdk.vm.ci.code.InstalledCode;
@@ -65,7 +66,7 @@
 
     @Test
     public void testEquals() {
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             // StringSubstitutions are disabled in 1.9
             return;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -130,7 +130,7 @@
     }
 
     @Override
-    protected boolean checkHighTierGraph(StructuredGraph graph) {
+    protected void checkHighTierGraph(StructuredGraph graph) {
         // Check that the graph contains the expected test nodes.
         NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
         Assert.assertTrue("expected exactly one ReturnNode", retNodes.count() == 1);
@@ -151,8 +151,6 @@
         value.safeDelete();
         guard.safeDelete();
         graph.removeFixed(memory);
-
-        return true;
     }
 
     @Test
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -109,6 +109,7 @@
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecode;
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 
 import jdk.vm.ci.meta.ConstantPool;
 import jdk.vm.ci.meta.JavaField;
@@ -153,7 +154,7 @@
 
         Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
 
-        String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path";
+        String propertyName = JavaVersionUtil.JAVA_SPEC <= 8 ? "sun.boot.class.path" : "jdk.module.path";
         String bootclasspath = System.getProperty(propertyName);
         Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -54,6 +54,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.replacements.test.ReplacementsTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
 import org.junit.Assert;
 import org.junit.Test;
@@ -110,7 +111,7 @@
             return;
         }
         String recursionPropName = getClass().getName() + ".recursion";
-        if (Java8OrEarlier || Boolean.getBoolean(recursionPropName)) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8 || Boolean.getBoolean(recursionPropName)) {
             testHelper();
         } else {
             List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
@@ -206,7 +207,7 @@
         assumeTrue("VM name not in <pid>@<host> format: " + vmName, p != -1);
         String pid = vmName.substring(0, p);
         Class<?> c;
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             ClassLoader cl = ToolProvider.getSystemToolClassLoader();
             c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl);
         } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Fri Jun 28 14:36:42 2019 +0530
@@ -46,9 +46,10 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 
 import jdk.vm.ci.code.Architecture;
@@ -65,11 +66,13 @@
     protected final OptimisticOptimizations optimisticOpts;
     private final AllowAssumptions allowAssumptions;
     private final EconomicMap<ResolvedJavaMethod, EncodedGraph> graphCache;
+    private final BasePhase<? super CoreProviders> postParsingPhase;
 
     public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
                     AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
-                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) {
+                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider,
+                    BasePhase<? super CoreProviders> postParsingPhase) {
         super(architecture, graph, providers, loopExplosionPlugin,
                         invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod, sourceLanguagePositionProvider);
 
@@ -77,6 +80,7 @@
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
         this.allowAssumptions = allowAssumptions;
+        this.postParsingPhase = postParsingPhase;
         this.graphCache = EconomicMap.create();
     }
 
@@ -90,7 +94,7 @@
         if (isSubstitution && (UseEncodedGraphs.getValue(options) || IS_IN_NATIVE_IMAGE)) {
             // These must go through Replacements to find the graph to use.
             graphToEncode = providers.getReplacements().getMethodSubstitution(plugin, method, INLINE_AFTER_PARSING, allowAssumptions,
-                            options);
+                            null, options);
         } else {
             graphToEncode = buildGraph(method, plugin, intrinsicBytecodeProvider, isSubstitution);
         }
@@ -101,8 +105,7 @@
          * initial graph.
          */
         try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) {
-            PhaseContext context = new PhaseContext(providers);
-            new ConvertDeoptimizeToGuardPhase().apply(graphToEncode, context);
+            new ConvertDeoptimizeToGuardPhase().apply(graphToEncode, providers);
         } catch (Throwable t) {
             throw debug.handle(t);
         }
@@ -125,13 +128,14 @@
         // @formatter:on
         try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) {
             IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null
-                            ? new IntrinsicContext(method, plugin.getSubstitute(providers.getMetaAccess()), intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null;
+                            ? new IntrinsicContext(method, plugin.getSubstitute(providers.getMetaAccess()), intrinsicBytecodeProvider, INLINE_AFTER_PARSING)
+                            : null;
             GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext);
             graphBuilderPhaseInstance.apply(graphToEncode);
-
-            PhaseContext context = new PhaseContext(providers);
-            new CanonicalizerPhase().apply(graphToEncode, context);
-
+            new CanonicalizerPhase().apply(graphToEncode, providers);
+            if (postParsingPhase != null) {
+                postParsingPhase.apply(graphToEncode, providers);
+            }
         } catch (Throwable ex) {
             throw debug.handle(ex);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java	Fri Jun 28 14:36:42 2019 +0530
@@ -55,26 +55,28 @@
 
     @Override
     public FloatingNode interceptParameter(GraphBuilderTool b, int index, StampPair stamp) {
-        Object arg = constantArgs[index];
-        if (arg != null) {
-            ConstantNode constantNode;
-            if (arg instanceof ConstantNode) {
-                ConstantNode otherCon = (ConstantNode) arg;
-                if (otherCon.graph() != b.getGraph()) {
-                    /*
-                     * This is a node from another graph, so copy over extra state into a new
-                     * ConstantNode.
-                     */
-                    constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), otherCon.getValue(), otherCon.getStableDimension(), otherCon.isDefaultStable(), metaAccess);
+        if (index < constantArgs.length) {
+            Object arg = constantArgs[index];
+            if (arg != null) {
+                ConstantNode constantNode;
+                if (arg instanceof ConstantNode) {
+                    ConstantNode otherCon = (ConstantNode) arg;
+                    if (otherCon.graph() != b.getGraph()) {
+                        /*
+                         * This is a node from another graph, so copy over extra state into a new
+                         * ConstantNode.
+                         */
+                        constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), otherCon.getValue(), otherCon.getStableDimension(), otherCon.isDefaultStable(), metaAccess);
+                    } else {
+                        constantNode = otherCon;
+                    }
+                } else if (arg instanceof Constant) {
+                    constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), (Constant) arg, metaAccess);
                 } else {
-                    constantNode = otherCon;
+                    constantNode = ConstantNode.forConstant(snippetReflection.forBoxed(stamp.getTrustedStamp().getStackKind(), arg), metaAccess);
                 }
-            } else if (arg instanceof Constant) {
-                constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), (Constant) arg, metaAccess);
-            } else {
-                constantNode = ConstantNode.forConstant(snippetReflection.forBoxed(stamp.getTrustedStamp().getStackKind(), arg), metaAccess);
+                return constantNode;
             }
-            return constantNode;
         }
         return null;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Fri Jun 28 14:36:42 2019 +0530
@@ -48,7 +48,6 @@
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
-import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -140,7 +139,6 @@
 import org.graalvm.compiler.replacements.SnippetLowerableMemoryNode.SnippetLowering;
 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
-import org.graalvm.compiler.word.WordTypes;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.code.CodeUtil;
@@ -166,7 +164,6 @@
     protected final TargetDescription target;
     private final boolean useCompressedOops;
     private final ResolvedJavaType objectArrayType;
-    private final WordTypes wordTypes;
 
     private BoxingSnippets.Templates boxingSnippets;
     private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
@@ -177,7 +174,6 @@
         this.target = target;
         this.useCompressedOops = useCompressedOops;
         this.objectArrayType = metaAccess.lookupJavaType(Object[].class);
-        this.wordTypes = new WordTypes(metaAccess, target.wordJavaKind);
     }
 
     public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
@@ -436,6 +432,10 @@
     }
 
     public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index) {
+        return createArrayAddress(graph, array, elementKind, elementKind, index);
+    }
+
+    public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, JavaKind arrayKind, JavaKind elementKind, ValueNode index) {
         ValueNode wordIndex;
         if (target.wordSize > 4) {
             wordIndex = graph.unique(new SignExtendNode(index, target.wordSize * 8));
@@ -447,14 +447,14 @@
         int shift = CodeUtil.log2(metaAccess.getArrayIndexScale(elementKind));
         ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph)));
 
-        int base = metaAccess.getArrayBaseOffset(elementKind);
+        int base = metaAccess.getArrayBaseOffset(arrayKind);
         ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordJavaKind, base, graph)));
 
         return graph.unique(new OffsetAddressNode(array, offset));
     }
 
     protected void lowerIndexAddressNode(IndexAddressNode indexAddress) {
-        AddressNode lowered = createArrayAddress(indexAddress.graph(), indexAddress.getArray(), indexAddress.getElementKind(), indexAddress.getIndex());
+        AddressNode lowered = createArrayAddress(indexAddress.graph(), indexAddress.getArray(), indexAddress.getArrayKind(), indexAddress.getElementKind(), indexAddress.getIndex());
         indexAddress.replaceAndDelete(lowered);
     }
 
@@ -517,7 +517,7 @@
 
         AddressNode address = createArrayIndexAddress(graph, array, elementKind, storeIndexed.index(), boundsCheck);
         WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
-                        arrayStoreBarrierType(array, storeIndexed.elementKind())));
+                        arrayStoreBarrierType(storeIndexed.elementKind())));
         memoryWrite.setGuard(boundsCheck);
         if (condition != null) {
             tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile);
@@ -792,11 +792,11 @@
                                 long offset = fieldOffset(field);
                                 if (offset >= 0) {
                                     address = createOffsetAddress(graph, newObject, offset);
-                                    barrierType = fieldInitializationBarrier(field);
+                                    barrierType = fieldInitializationBarrier(entryKind);
                                 }
                             } else {
                                 address = createOffsetAddress(graph, newObject, metaAccess.getArrayBaseOffset(entryKind) + i * metaAccess.getArrayIndexScale(entryKind));
-                                barrierType = arrayInitializationBarrier(newObject, entryKind);
+                                barrierType = arrayInitializationBarrier(entryKind);
                             }
                             if (address != null) {
                                 WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
@@ -829,7 +829,7 @@
                                     barrierType = fieldStoreBarrierType(virtualInstance.field(i));
                                 } else {
                                     address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
-                                    barrierType = arrayStoreBarrierType(newObject, virtual.entryKind(i));
+                                    barrierType = arrayStoreBarrierType(virtual.entryKind(i));
                                 }
                                 if (address != null) {
                                     WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
@@ -943,50 +943,25 @@
     }
 
     protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
-        JavaKind fieldKind = wordTypes.asKind(field.getType());
-        if (fieldKind == JavaKind.Object) {
+        if (getStorageKind(field) == JavaKind.Object) {
             return BarrierType.FIELD;
         }
         return BarrierType.NONE;
     }
 
-    /**
-     * If the given value is indeed an array, and its elements are of a word type, return the
-     * correct word kind; in all other cases, return the defaultElementKind. This is needed for
-     * determining the correct write barrier type.
-     *
-     * @param array a value that is expected to have an array stamp
-     * @param defaultElementKind the array's element kind without taking word types into account
-     * @return the element kind of the array taking word types into account
-     */
-    protected JavaKind maybeWordArrayElementKind(ValueNode array, JavaKind defaultElementKind) {
-        JavaKind elementKind = defaultElementKind;
-        Stamp arrayStamp = array.stamp(NodeView.DEFAULT);
-        if (arrayStamp instanceof AbstractObjectStamp && arrayStamp.hasValues()) {
-            ResolvedJavaType arrayType = ((AbstractObjectStamp) arrayStamp).type();
-            if (arrayType != null && arrayType.getComponentType() != null) {
-                elementKind = wordTypes.asKind(arrayType.getComponentType());
-            }
-        }
-        return elementKind;
-    }
-
-    protected BarrierType arrayStoreBarrierType(ValueNode array, JavaKind elementKind) {
-        JavaKind kind = maybeWordArrayElementKind(array, elementKind);
-        if (kind == JavaKind.Object) {
+    protected BarrierType arrayStoreBarrierType(JavaKind elementKind) {
+        if (elementKind == JavaKind.Object) {
             return BarrierType.ARRAY;
         }
         return BarrierType.NONE;
     }
 
-    public BarrierType fieldInitializationBarrier(ResolvedJavaField field) {
-        JavaKind fieldKind = wordTypes.asKind(field.getType());
-        return fieldKind == JavaKind.Object ? BarrierType.FIELD : BarrierType.NONE;
+    public BarrierType fieldInitializationBarrier(JavaKind entryKind) {
+        return entryKind == JavaKind.Object ? BarrierType.FIELD : BarrierType.NONE;
     }
 
-    public BarrierType arrayInitializationBarrier(ValueNode array, JavaKind entryKind) {
-        JavaKind kind = maybeWordArrayElementKind(array, entryKind);
-        return kind == JavaKind.Object ? BarrierType.ARRAY : BarrierType.NONE;
+    public BarrierType arrayInitializationBarrier(JavaKind entryKind) {
+        return entryKind == JavaKind.Object ? BarrierType.ARRAY : BarrierType.NONE;
     }
 
     private BarrierType unsafeStoreBarrierType(RawStoreNode store) {
@@ -1002,9 +977,7 @@
             // Array types must use a precise barrier, so if the type is unknown or is a supertype
             // of Object[] then treat it as an array.
             if (type != null && type.isArray()) {
-                return arrayStoreBarrierType(object, JavaKind.Object);
-            } else if (type != null && wordTypes.isWord(type)) {
-                return BarrierType.NONE;
+                return BarrierType.ARRAY;
             } else if (type == null || type.isAssignableFrom(objectArrayType)) {
                 return BarrierType.UNKNOWN;
             } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/Log.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.replacements;
-
-import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
-
-import java.io.PrintStream;
-
-import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-import org.graalvm.compiler.nodes.extended.ForeignCallNode;
-import org.graalvm.compiler.word.Word;
-
-import jdk.vm.ci.meta.JavaKind;
-
-//JaCoCo Exclude
-
-/**
- * Provides {@link PrintStream}-like logging facility.
- */
-public final class Log {
-
-    public static final ForeignCallDescriptor LOG_PRIMITIVE = new ForeignCallDescriptor("logPrimitive", void.class, int.class, long.class, boolean.class);
-    public static final ForeignCallDescriptor LOG_OBJECT = new ForeignCallDescriptor("logObject", void.class, Object.class, boolean.class, boolean.class);
-    public static final ForeignCallDescriptor LOG_PRINTF = new ForeignCallDescriptor("logPrintf", void.class, Word.class, long.class, long.class, long.class);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logObject, Object object, boolean asString, boolean newline);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    private static native void log(@ConstantNodeParameter ForeignCallDescriptor logPrimitive, int typeChar, long value, boolean newline);
-
-    @NodeIntrinsic(ForeignCallNode.class)
-    private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, Word format, long v1, long v2, long v3);
-
-    public static void print(boolean value) {
-        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, false);
-    }
-
-    public static void print(byte value) {
-        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, false);
-    }
-
-    public static void print(char value) {
-        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, false);
-    }
-
-    public static void print(short value) {
-        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, false);
-    }
-
-    public static void print(int value) {
-        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, false);
-    }
-
-    public static void print(long value) {
-        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, false);
-    }
-
-    /**
-     * Prints a formatted string to the log stream.
-     *
-     * @param format a C style printf format value that can contain at most one conversion specifier
-     *            (i.e., a sequence of characters starting with '%').
-     * @param value the value associated with the conversion specifier
-     */
-    public static void printf(String format, long value) {
-        printf(LOG_PRINTF, cstring(format), value, 0L, 0L);
-    }
-
-    public static void printf(String format, long v1, long v2) {
-        printf(LOG_PRINTF, cstring(format), v1, v2, 0L);
-    }
-
-    public static void printf(String format, long v1, long v2, long v3) {
-        printf(LOG_PRINTF, cstring(format), v1, v2, v3);
-    }
-
-    public static void print(float value) {
-        if (Float.isNaN(value)) {
-            print("NaN");
-        } else if (value == Float.POSITIVE_INFINITY) {
-            print("Infinity");
-        } else if (value == Float.NEGATIVE_INFINITY) {
-            print("-Infinity");
-        } else {
-            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), false);
-        }
-    }
-
-    public static void print(double value) {
-        if (Double.isNaN(value)) {
-            print("NaN");
-        } else if (value == Double.POSITIVE_INFINITY) {
-            print("Infinity");
-        } else if (value == Double.NEGATIVE_INFINITY) {
-            print("-Infinity");
-        } else {
-            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false);
-        }
-    }
-
-    public static void print(String value) {
-        log(LOG_OBJECT, value, true, false);
-    }
-
-    public static void printObject(Object o) {
-        log(LOG_OBJECT, o, false, false);
-    }
-
-    public static void println(boolean value) {
-        log(LOG_PRIMITIVE, JavaKind.Boolean.getTypeChar(), value ? 1L : 0L, true);
-    }
-
-    public static void println(byte value) {
-        log(LOG_PRIMITIVE, JavaKind.Byte.getTypeChar(), value, true);
-    }
-
-    public static void println(char value) {
-        log(LOG_PRIMITIVE, JavaKind.Char.getTypeChar(), value, true);
-    }
-
-    public static void println(short value) {
-        log(LOG_PRIMITIVE, JavaKind.Short.getTypeChar(), value, true);
-    }
-
-    public static void println(int value) {
-        log(LOG_PRIMITIVE, JavaKind.Int.getTypeChar(), value, true);
-    }
-
-    public static void println(long value) {
-        log(LOG_PRIMITIVE, JavaKind.Long.getTypeChar(), value, true);
-    }
-
-    public static void println(float value) {
-        if (Float.isNaN(value)) {
-            println("NaN");
-        } else if (value == Float.POSITIVE_INFINITY) {
-            println("Infinity");
-        } else if (value == Float.NEGATIVE_INFINITY) {
-            println("-Infinity");
-        } else {
-            log(LOG_PRIMITIVE, JavaKind.Float.getTypeChar(), Float.floatToRawIntBits(value), true);
-        }
-    }
-
-    public static void println(double value) {
-        if (Double.isNaN(value)) {
-            println("NaN");
-        } else if (value == Double.POSITIVE_INFINITY) {
-            println("Infinity");
-        } else if (value == Double.NEGATIVE_INFINITY) {
-            println("-Infinity");
-        } else {
-            log(LOG_PRIMITIVE, JavaKind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true);
-        }
-    }
-
-    public static void println(String value) {
-        log(LOG_OBJECT, value, true, true);
-    }
-
-    public static void printlnObject(Object o) {
-        log(LOG_OBJECT, o, false, true);
-    }
-
-    public static void println() {
-        println("");
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri Jun 28 14:36:42 2019 +0530
@@ -67,6 +67,7 @@
 import org.graalvm.compiler.java.GraphBuilderPhase.Instance;
 import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.nodes.CallTargetNode;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -86,7 +87,6 @@
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordOperationPlugin;
@@ -263,7 +263,7 @@
 
     @Override
     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
-                    StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
+                    StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
         // Method substitutions are parsed by the BytecodeParser.
         return null;
     }
@@ -330,7 +330,7 @@
 
     @SuppressWarnings("try")
     @Override
-    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) {
+    public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug, Cancellable cancellable) {
         MethodSubstitutionPlugin msPlugin = getMethodSubstitution(method);
         if (msPlugin != null) {
             ResolvedJavaMethod substMethod = msPlugin.getSubstitute(providers.getMetaAccess());
@@ -560,7 +560,7 @@
 
                 createGraphBuilder(replacements.providers, config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
 
-                new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
+                new CanonicalizerPhase().apply(graph, replacements.providers);
             } catch (Throwable e) {
                 throw debug.handle(e);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri Jun 28 14:36:42 2019 +0530
@@ -119,6 +119,7 @@
 import org.graalvm.compiler.nodes.memory.MemoryNode;
 import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.spi.MemoryProxy;
 import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -133,7 +134,6 @@
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode;
@@ -633,6 +633,10 @@
             }
         }
 
+        public Providers getProviders() {
+            return providers;
+        }
+
         public static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
             for (Method m : declaringClass.getDeclaredMethods()) {
                 if (m.getName().equals(methodName) && !m.equals(except)) {
@@ -698,7 +702,7 @@
          * Gets a template for a given key, creating it first if necessary.
          */
         @SuppressWarnings("try")
-        protected SnippetTemplate template(ValueNode replacee, final Arguments args) {
+        public SnippetTemplate template(ValueNode replacee, final Arguments args) {
             StructuredGraph graph = replacee.graph();
             DebugContext outer = graph.getDebug();
             SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? templates.get(args.cacheKey) : null;
@@ -770,8 +774,6 @@
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
 
-        PhaseContext phaseContext = new PhaseContext(providers);
-
         // Copy snippet graph, replacing constant parameters with given arguments
         final StructuredGraph snippetCopy = new StructuredGraph.Builder(options, debug).name(snippetGraph.name).method(snippetGraph.method()).trackNodeSourcePosition(
                         snippetGraph.trackNodeSourcePosition()).setIsSubstitution(true).build();
@@ -880,7 +882,7 @@
                 }
             }
 
-            explodeLoops(snippetCopy, phaseContext);
+            explodeLoops(snippetCopy, providers);
 
             GuardsStage guardsStage = args.cacheKey.guardsStage;
             // Perform lowering on the snippet
@@ -889,7 +891,7 @@
             }
             snippetCopy.setGuardsStage(guardsStage);
             try (DebugContext.Scope s = debug.scope("LoweringSnippetTemplate", snippetCopy)) {
-                new LoweringPhase(new CanonicalizerPhase(), args.cacheKey.loweringStage).apply(snippetCopy, phaseContext);
+                new LoweringPhase(new CanonicalizerPhase(), args.cacheKey.loweringStage).apply(snippetCopy, providers);
             } catch (Throwable e) {
                 throw debug.handle(e);
             }
@@ -1045,7 +1047,7 @@
         return true;
     }
 
-    public static void explodeLoops(final StructuredGraph snippetCopy, PhaseContext phaseContext) {
+    public static void explodeLoops(final StructuredGraph snippetCopy, CoreProviders providers) {
         // Do any required loop explosion
         boolean exploded = false;
         do {
@@ -1057,8 +1059,8 @@
                 if (loopBegin != null) {
                     LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
                     Mark mark = snippetCopy.getMark();
-                    LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase());
-                    new CanonicalizerPhase().applyIncremental(snippetCopy, phaseContext, mark, false);
+                    LoopTransformations.fullUnroll(loop, providers, new CanonicalizerPhase());
+                    new CanonicalizerPhase().applyIncremental(snippetCopy, providers, mark, false);
                     loop.deleteUnusedNodes();
                 }
                 GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri Jun 28 14:36:42 2019 +0530
@@ -33,8 +33,6 @@
 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
 import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java11OrEarlier;
-import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.Java8OrEarlier;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
@@ -133,6 +131,7 @@
 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactOverflowNode;
 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
@@ -188,7 +187,7 @@
         Field coder = null;
         try {
             STRING_VALUE_FIELD = String.class.getDeclaredField("value");
-            if (!Java8OrEarlier) {
+            if (JavaVersionUtil.JAVA_SPEC > 8) {
                 coder = String.class.getDeclaredField("coder");
             }
         } catch (NoSuchFieldException e) {
@@ -227,7 +226,7 @@
             }
         });
 
-        if (Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
 
             r.register7("indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class, new StringIndexOfConstantPlugin());
@@ -384,7 +383,7 @@
 
     public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds) {
         registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
         }
 
@@ -394,14 +393,14 @@
         if (java8OrEarlier) {
             unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSwap", explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true);
         } else {
-            unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSet", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier);
-            unsafeCompareAndExchangePluginsRegistrar.register(r, "compareAndExchange", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier);
+            unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSet", explicitUnsafeNullChecks, supportedCasKinds, JavaVersionUtil.JAVA_SPEC <= 11);
+            unsafeCompareAndExchangePluginsRegistrar.register(r, "compareAndExchange", explicitUnsafeNullChecks, supportedCasKinds, JavaVersionUtil.JAVA_SPEC <= 11);
         }
     }
 
     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
-        if (!Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
         }
     }
@@ -410,7 +409,7 @@
         for (JavaKind kind : JavaKind.values()) {
             if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
                 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
-                String kindName = (kind == JavaKind.Object && !sunMiscUnsafe && !Java11OrEarlier) ? "Reference" : kind.name();
+                String kindName = (kind == JavaKind.Object && !sunMiscUnsafe && !(JavaVersionUtil.JAVA_SPEC <= 11)) ? "Reference" : kind.name();
                 String getName = "get" + kindName;
                 String putName = "put" + kindName;
                 // Object-based accesses
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/G1WriteBarrierSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.replacements.gc;
+
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.extended.NullCheckNode;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ArrayRangePreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PostWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1PreWriteBarrier;
+import org.graalvm.compiler.nodes.gc.G1ReferentFieldReadBarrier;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetCounter.Group;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+import org.graalvm.compiler.replacements.nodes.CStringConstant;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+import jdk.internal.vm.compiler.word.Pointer;
+import jdk.internal.vm.compiler.word.UnsignedWord;
+import jdk.internal.vm.compiler.word.WordFactory;
+
+public abstract class G1WriteBarrierSnippets extends WriteBarrierSnippets implements Snippets {
+
+    public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log");
+    public static final LocationIdentity GC_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Index");
+    public static final LocationIdentity SATB_QUEUE_MARKING_LOCATION = NamedLocationIdentity.mutable("GC-Queue-Marking");
+    public static final LocationIdentity SATB_QUEUE_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Queue-Index");
+    public static final LocationIdentity SATB_QUEUE_BUFFER_LOCATION = NamedLocationIdentity.mutable("GC-Queue-Buffer");
+    public static final LocationIdentity CARD_QUEUE_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Card-Queue-Index");
+    public static final LocationIdentity CARD_QUEUE_BUFFER_LOCATION = NamedLocationIdentity.mutable("GC-Card-Queue-Buffer");
+
+    public static class Counters {
+        Counters(SnippetCounter.Group.Factory factory) {
+            Group countersWriteBarriers = factory.createSnippetCounterGroup("G1 WriteBarriers");
+            g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of attempted G1 Pre Write Barriers");
+            g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of effective G1 Pre Write Barriers");
+            g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of executed G1 Pre Write Barriers");
+            g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
+            g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
+                            "Number of effective G1 Post Write Barriers (after passing the XOR test)");
+            g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
+                            "Number of effective G1 Post Write Barriers (after passing the NULL test)");
+            g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
+        }
+
+        final SnippetCounter g1AttemptedPreWriteBarrierCounter;
+        final SnippetCounter g1EffectivePreWriteBarrierCounter;
+        final SnippetCounter g1ExecutedPreWriteBarrierCounter;
+        final SnippetCounter g1AttemptedPostWriteBarrierCounter;
+        final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter;
+        final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter;
+        final SnippetCounter g1ExecutedPostWriteBarrierCounter;
+    }
+
+    @Snippet
+    public void g1PreWriteBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
+                    @ConstantParameter int traceStartCycle, @ConstantParameter Counters counters) {
+        if (nullCheck) {
+            NullCheckNode.nullCheck(address);
+        }
+        Word thread = getThread();
+        verifyOop(object);
+        Word field = Word.fromAddress(address);
+        byte markingValue = thread.readByte(satbQueueMarkingOffset(), SATB_QUEUE_MARKING_LOCATION);
+
+        boolean trace = isTracingActive(traceStartCycle);
+        int gcCycle = 0;
+        if (trace) {
+            Pointer gcTotalCollectionsAddress = WordFactory.pointer(gcTotalCollectionsAddress());
+            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
+            log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(expectedObject).rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
+            log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
+            log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
+        }
+
+        counters.g1AttemptedPreWriteBarrierCounter.inc();
+        // If the concurrent marker is enabled, the barrier is issued.
+        if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
+            // If the previous value has to be loaded (before the write), the load is issued.
+            // The load is always issued except the cases of CAS and referent field.
+            Object previousObject;
+            if (doLoad) {
+                previousObject = field.readObject(0, BarrierType.NONE);
+                if (trace) {
+                    log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(previousObject).rawValue());
+                    verifyOop(previousObject);
+                }
+            } else {
+                previousObject = FixedValueAnchorNode.getObject(expectedObject);
+            }
+
+            counters.g1EffectivePreWriteBarrierCounter.inc();
+            // If the previous value is null the barrier should not be issued.
+            if (probability(FREQUENT_PROBABILITY, previousObject != null)) {
+                counters.g1ExecutedPreWriteBarrierCounter.inc();
+                // If the thread-local SATB buffer is full issue a native call which will
+                // initialize a new one and add the entry.
+                Word indexAddress = thread.add(satbQueueIndexOffset());
+                Word indexValue = indexAddress.readWord(0, SATB_QUEUE_INDEX_LOCATION);
+                if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
+                    Word bufferAddress = thread.readWord(satbQueueBufferOffset(), SATB_QUEUE_BUFFER_LOCATION);
+                    Word nextIndex = indexValue.subtract(wordSize());
+                    Word logAddress = bufferAddress.add(nextIndex);
+                    // Log the object to be marked as well as update the SATB's buffer next index.
+                    Word previousOop = Word.objectToTrackedPointer(previousObject);
+                    logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
+                } else {
+                    g1PreBarrierStub(previousObject);
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter int traceStartCycle,
+                    @ConstantParameter Counters counters) {
+        Word thread = getThread();
+        Object fixedValue = FixedValueAnchorNode.getObject(value);
+        verifyOop(object);
+        verifyOop(fixedValue);
+        validateObject(object, fixedValue);
+
+        Pointer oop;
+        if (usePrecise) {
+            oop = Word.fromAddress(address);
+        } else {
+            if (verifyBarrier()) {
+                verifyNotArray(object);
+            }
+            oop = Word.objectToTrackedPointer(object);
+        }
+
+        boolean trace = isTracingActive(traceStartCycle);
+        int gcCycle = 0;
+        if (trace) {
+            Pointer gcTotalCollectionsAddress = WordFactory.pointer(gcTotalCollectionsAddress());
+            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
+            log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
+            log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
+        }
+        Pointer writtenValue = Word.objectToTrackedPointer(fixedValue);
+        // The result of the xor reveals whether the installed pointer crosses heap regions.
+        // In case it does the write barrier has to be issued.
+        final int logOfHeapRegionGrainBytes = logOfHeapRegionGrainBytes();
+        UnsignedWord xorResult = (oop.xor(writtenValue)).unsignedShiftRight(logOfHeapRegionGrainBytes);
+
+        counters.g1AttemptedPostWriteBarrierCounter.inc();
+        if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
+            counters.g1EffectiveAfterXORPostWriteBarrierCounter.inc();
+            // If the written value is not null continue with the barrier addition.
+            if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
+                // Calculate the address of the card to be enqueued to the
+                // thread local card queue.
+                Word cardAddress = cardTableAddress().add(oop.unsignedShiftRight(cardTableShift()));
+
+                byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
+                counters.g1EffectiveAfterNullPostWriteBarrierCounter.inc();
+
+                // If the card is already dirty, (hence already enqueued) skip the insertion.
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByte != youngCardValue())) {
+                    MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
+                    byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
+                    if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue())) {
+                        log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), WordFactory.unsigned((int) cardByte).rawValue());
+                        cardAddress.writeByte(0, dirtyCardValue(), GC_CARD_LOCATION);
+                        counters.g1ExecutedPostWriteBarrierCounter.inc();
+
+                        // If the thread local card queue is full, issue a native call which will
+                        // initialize a new one and add the card entry.
+                        Word indexValue = thread.readWord(cardQueueIndexOffset(), CARD_QUEUE_INDEX_LOCATION);
+                        if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
+                            Word bufferAddress = thread.readWord(cardQueueBufferOffset(), CARD_QUEUE_BUFFER_LOCATION);
+                            Word nextIndex = indexValue.subtract(wordSize());
+                            Word logAddress = bufferAddress.add(nextIndex);
+                            Word indexAddress = thread.add(cardQueueIndexOffset());
+                            // Log the object to be scanned as well as update
+                            // the card queue's next index.
+                            logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
+                            indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
+                        } else {
+                            g1PostBarrierStub(cardAddress);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
+        Word thread = getThread();
+        byte markingValue = thread.readByte(satbQueueMarkingOffset(), SATB_QUEUE_MARKING_LOCATION);
+        // If the concurrent marker is not enabled or the vector length is zero, return.
+        if (probability(FREQUENT_PROBABILITY, markingValue == (byte) 0 || length == 0)) {
+            return;
+        }
+
+        Word bufferAddress = thread.readWord(satbQueueBufferOffset(), SATB_QUEUE_BUFFER_LOCATION);
+        Word indexAddress = thread.add(satbQueueIndexOffset());
+        long indexValue = indexAddress.readWord(0, SATB_QUEUE_INDEX_LOCATION).rawValue();
+        int scale = objectArrayIndexScale();
+        Word start = getPointerToFirstArrayElement(address, length, elementStride);
+
+        for (int i = 0; i < length; i++) {
+            Word arrElemPtr = start.add(i * scale);
+            Object previousObject = arrElemPtr.readObject(0, BarrierType.NONE);
+            verifyOop(previousObject);
+            if (probability(FREQUENT_PROBABILITY, previousObject != null)) {
+                if (probability(FREQUENT_PROBABILITY, indexValue != 0)) {
+                    indexValue = indexValue - wordSize();
+                    Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
+                    // Log the object to be marked as well as update the SATB's buffer next index.
+                    Word previousOop = Word.objectToTrackedPointer(previousObject);
+                    logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
+                    indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
+                } else {
+                    g1PreBarrierStub(previousObject);
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public void g1ArrayRangePostWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
+        if (probability(NOT_FREQUENT_PROBABILITY, length == 0)) {
+            return;
+        }
+
+        Word thread = getThread();
+        Word bufferAddress = thread.readWord(cardQueueBufferOffset(), CARD_QUEUE_BUFFER_LOCATION);
+        Word indexAddress = thread.add(cardQueueIndexOffset());
+        long indexValue = thread.readWord(cardQueueIndexOffset(), CARD_QUEUE_INDEX_LOCATION).rawValue();
+
+        int cardShift = cardTableShift();
+        Word cardStart = cardTableAddress();
+        Word start = cardStart.add(getPointerToFirstArrayElement(address, length, elementStride).unsignedShiftRight(cardShift));
+        Word end = cardStart.add(getPointerToLastArrayElement(address, length, elementStride).unsignedShiftRight(cardShift));
+
+        Word cur = start;
+        do {
+            byte cardByte = cur.readByte(0, GC_CARD_LOCATION);
+            // If the card is already dirty, (hence already enqueued) skip the insertion.
+            if (probability(NOT_FREQUENT_PROBABILITY, cardByte != youngCardValue())) {
+                MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
+                byte cardByteReload = cur.readByte(0, GC_CARD_LOCATION);
+                if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue())) {
+                    cur.writeByte(0, dirtyCardValue(), GC_CARD_LOCATION);
+                    // If the thread local card queue is full, issue a native call which will
+                    // initialize a new one and add the card entry.
+                    if (probability(FREQUENT_PROBABILITY, indexValue != 0)) {
+                        indexValue = indexValue - wordSize();
+                        Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
+                        // Log the object to be scanned as well as update
+                        // the card queue's next index.
+                        logAddress.writeWord(0, cur, GC_LOG_LOCATION);
+                        indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
+                    } else {
+                        g1PostBarrierStub(cur);
+                    }
+                }
+            }
+            cur = cur.add(1);
+        } while (cur.belowOrEqual(end));
+    }
+
+    protected abstract Word getThread();
+
+    protected abstract int wordSize();
+
+    protected abstract int objectArrayIndexScale();
+
+    protected abstract int satbQueueMarkingOffset();
+
+    protected abstract int satbQueueBufferOffset();
+
+    protected abstract int satbQueueIndexOffset();
+
+    protected abstract int cardQueueBufferOffset();
+
+    protected abstract int cardQueueIndexOffset();
+
+    protected abstract byte dirtyCardValue();
+
+    protected abstract byte youngCardValue();
+
+    protected abstract Word cardTableAddress();
+
+    protected abstract int cardTableShift();
+
+    protected abstract int logOfHeapRegionGrainBytes();
+
+    protected abstract ForeignCallDescriptor preWriteBarrierCallDescriptor();
+
+    protected abstract ForeignCallDescriptor postWriteBarrierCallDescriptor();
+
+    // the data below is only needed for the verification logic
+    protected abstract boolean verifyOops();
+
+    protected abstract boolean verifyBarrier();
+
+    protected abstract long gcTotalCollectionsAddress();
+
+    protected abstract ForeignCallDescriptor verifyOopCallDescriptor();
+
+    protected abstract ForeignCallDescriptor validateObjectCallDescriptor();
+
+    protected abstract ForeignCallDescriptor printfCallDescriptor();
+
+    private boolean isTracingActive(int traceStartCycle) {
+        return traceStartCycle > 0 && ((Pointer) WordFactory.pointer(gcTotalCollectionsAddress())).readLong(0) > traceStartCycle;
+    }
+
+    private void log(boolean enabled, String format, long value1, long value2, long value3) {
+        if (enabled) {
+            printf(printfCallDescriptor(), CStringConstant.cstring(format), value1, value2, value3);
+        }
+    }
+
+    /**
+     * Validation helper method which performs sanity checks on write operations. The addresses of
+     * both the object and the value being written are checked in order to determine if they reside
+     * in a valid heap region. If an object is stale, an invalid access is performed in order to
+     * prematurely crash the VM and debug the stack trace of the faulty method.
+     */
+    private void validateObject(Object parent, Object child) {
+        if (verifyOops() && child != null) {
+            Word parentWord = Word.objectToTrackedPointer(parent);
+            Word childWord = Word.objectToTrackedPointer(child);
+            boolean success = validateOop(validateObjectCallDescriptor(), parentWord, childWord);
+            AssertionNode.assertion(false, success, "Verification ERROR, Parent: %p Child: %p\n", parentWord.rawValue(), childWord.rawValue());
+        }
+    }
+
+    private void verifyOop(Object object) {
+        if (verifyOops()) {
+            verifyOopStub(verifyOopCallDescriptor(), object);
+        }
+    }
+
+    private void g1PreBarrierStub(Object previousObject) {
+        g1PreBarrierStub(preWriteBarrierCallDescriptor(), previousObject);
+    }
+
+    private void g1PostBarrierStub(Word cardAddress) {
+        g1PostBarrierStub(postWriteBarrierCallDescriptor(), cardAddress);
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word parent, Word object);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void g1PreBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void g1PostBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word card);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void printf(@ConstantNodeParameter ForeignCallDescriptor logPrintf, Word format, long v1, long v2, long v3);
+
+    public abstract static class G1WriteBarrierLowerer {
+        private final Counters counters;
+
+        public G1WriteBarrierLowerer(Group.Factory factory) {
+            this.counters = new Counters(factory);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, G1PreWriteBarrier barrier, LoweringTool tool) {
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = barrier.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                args.add("object", null);
+            }
+
+            ValueNode expected = barrier.getExpectedObject();
+            if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
+                expected = uncompress(expected);
+            }
+            args.add("expectedObject", expected);
+
+            args.addConst("doLoad", barrier.doLoad());
+            args.addConst("nullCheck", barrier.getNullCheck());
+            args.addConst("traceStartCycle", traceStartCycle(barrier.graph()));
+            args.addConst("counters", counters);
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, G1ReferentFieldReadBarrier barrier, LoweringTool tool) {
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = barrier.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                args.add("object", null);
+            }
+
+            ValueNode expected = barrier.getExpectedObject();
+            if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
+                expected = uncompress(expected);
+            }
+
+            args.add("expectedObject", expected);
+            args.addConst("doLoad", barrier.doLoad());
+            args.addConst("nullCheck", false);
+            args.addConst("traceStartCycle", traceStartCycle(barrier.graph()));
+            args.addConst("counters", counters);
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, G1PostWriteBarrier barrier, LoweringTool tool) {
+            if (barrier.alwaysNull()) {
+                barrier.graph().removeFixed(barrier);
+                return;
+            }
+
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            AddressNode address = barrier.getAddress();
+            args.add("address", address);
+            if (address instanceof OffsetAddressNode) {
+                args.add("object", ((OffsetAddressNode) address).getBase());
+            } else {
+                assert barrier.usePrecise() : "found imprecise barrier that's not an object access " + barrier;
+                args.add("object", null);
+            }
+
+            ValueNode value = barrier.getValue();
+            if (value.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
+                value = uncompress(value);
+            }
+            args.add("value", value);
+
+            args.addConst("usePrecise", barrier.usePrecise());
+            args.addConst("traceStartCycle", traceStartCycle(barrier.graph()));
+            args.addConst("counters", counters);
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, G1ArrayRangePreWriteBarrier barrier, LoweringTool tool) {
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("address", barrier.getAddress());
+            args.add("length", barrier.getLength());
+            args.addConst("elementStride", barrier.getElementStride());
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, G1ArrayRangePostWriteBarrier barrier, LoweringTool tool) {
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("address", barrier.getAddress());
+            args.add("length", barrier.getLength());
+            args.addConst("elementStride", barrier.getElementStride());
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, SnippetTemplate.DEFAULT_REPLACER, args);
+        }
+
+        private static int traceStartCycle(StructuredGraph graph) {
+            return GraalOptions.GCDebugStartCycle.getValue(graph.getOptions());
+        }
+
+        protected abstract ValueNode uncompress(ValueNode value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/SerialWriteBarrierSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.replacements.gc;
+
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.nodes.gc.SerialArrayRangeWriteBarrier;
+import org.graalvm.compiler.nodes.gc.SerialWriteBarrier;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.replacements.SnippetCounter;
+import org.graalvm.compiler.replacements.SnippetCounter.Group;
+import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
+import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
+import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.Pointer;
+
+public abstract class SerialWriteBarrierSnippets extends WriteBarrierSnippets implements Snippets {
+    static class Counters {
+        Counters(SnippetCounter.Group.Factory factory) {
+            Group countersWriteBarriers = factory.createSnippetCounterGroup("Serial WriteBarriers");
+            serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
+        }
+
+        final SnippetCounter serialWriteBarrierCounter;
+    }
+
+    @Snippet
+    public void serialImpreciseWriteBarrier(Object object, @ConstantParameter Counters counters, @ConstantParameter boolean verifyOnly) {
+        if (verifyBarrier()) {
+            verifyNotArray(object);
+        }
+        serialWriteBarrier(Word.objectToTrackedPointer(object), counters, verifyOnly);
+    }
+
+    @Snippet
+    public void serialPreciseWriteBarrier(Address address, @ConstantParameter Counters counters, @ConstantParameter boolean verifyOnly) {
+        serialWriteBarrier(Word.fromAddress(address), counters, verifyOnly);
+    }
+
+    @Snippet
+    public void serialArrayRangeWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
+        if (probability(NOT_FREQUENT_PROBABILITY, length == 0)) {
+            return;
+        }
+
+        int cardShift = cardTableShift();
+        Word cardTableAddress = cardTableAddress();
+        Word start = cardTableAddress.add(getPointerToFirstArrayElement(address, length, elementStride).unsignedShiftRight(cardShift));
+        Word end = cardTableAddress.add(getPointerToLastArrayElement(address, length, elementStride).unsignedShiftRight(cardShift));
+
+        Word cur = start;
+        do {
+            cur.writeByte(0, dirtyCardValue(), GC_CARD_LOCATION);
+            cur = cur.add(1);
+        } while (cur.belowOrEqual(end));
+    }
+
+    private void serialWriteBarrier(Pointer ptr, Counters counters, boolean verifyOnly) {
+        if (!verifyOnly) {
+            counters.serialWriteBarrierCounter.inc();
+        }
+
+        Word base = cardTableAddress().add(ptr.unsignedShiftRight(cardTableShift()));
+        if (verifyOnly) {
+            byte cardValue = base.readByte(0, GC_CARD_LOCATION);
+            AssertionNode.assertion(false, cardValue == dirtyCardValue(), "card must be dirty");
+        } else {
+            base.writeByte(0, dirtyCardValue(), GC_CARD_LOCATION);
+        }
+    }
+
+    protected abstract Word cardTableAddress();
+
+    protected abstract int cardTableShift();
+
+    protected abstract boolean verifyBarrier();
+
+    protected abstract byte dirtyCardValue();
+
+    public static class SerialWriteBarrierLowerer {
+        private final Counters counters;
+
+        public SerialWriteBarrierLowerer(Group.Factory factory) {
+            this.counters = new Counters(factory);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo preciseSnippet, SnippetInfo impreciseSnippet, SerialWriteBarrier barrier, LoweringTool tool) {
+            Arguments args;
+            if (barrier.usePrecise()) {
+                args = new Arguments(preciseSnippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("address", barrier.getAddress());
+            } else {
+                args = new Arguments(impreciseSnippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+                OffsetAddressNode address = (OffsetAddressNode) barrier.getAddress();
+                args.add("object", address.getBase());
+            }
+            args.addConst("counters", counters);
+            args.addConst("verifyOnly", barrier.getVerifyOnly());
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, DEFAULT_REPLACER, args);
+        }
+
+        public void lower(AbstractTemplates templates, SnippetInfo snippet, SerialArrayRangeWriteBarrier barrier, LoweringTool tool) {
+            Arguments args = new Arguments(snippet, barrier.graph().getGuardsStage(), tool.getLoweringStage());
+            args.add("address", barrier.getAddress());
+            args.add("length", barrier.getLength());
+            args.addConst("elementStride", barrier.getElementStride());
+
+            templates.template(barrier, args).instantiate(templates.getProviders().getMetaAccess(), barrier, DEFAULT_REPLACER, args);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/gc/WriteBarrierSnippets.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.replacements.gc;
+
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.SnippetAnchorNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
+import org.graalvm.compiler.word.Word;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+import jdk.internal.vm.compiler.word.WordFactory;
+
+public abstract class WriteBarrierSnippets {
+    public static final LocationIdentity GC_CARD_LOCATION = NamedLocationIdentity.mutable("GC-Card");
+
+    protected static void verifyNotArray(Object object) {
+        if (object != null) {
+            // Manually build the null check and cast because we're in snippet that's lowered late.
+            AssertionNode.assertion(false, !PiNode.piCastNonNull(object, SnippetAnchorNode.anchor()).getClass().isArray(), "imprecise card mark used with array");
+        }
+    }
+
+    protected static Word getPointerToFirstArrayElement(Address address, int length, int elementStride) {
+        long result = Word.fromAddress(address).rawValue();
+        if (elementStride < 0) {
+            // the address points to the place after the last array element
+            result = result + elementStride * length;
+        }
+        return WordFactory.unsigned(result);
+    }
+
+    protected static Word getPointerToLastArrayElement(Address address, int length, int elementStride) {
+        long result = Word.fromAddress(address).rawValue();
+        if (elementStride < 0) {
+            // the address points to the place after the last array element
+            result = result + elementStride;
+        } else {
+            result = result + (length - 1) * elementStride;
+        }
+        return WordFactory.unsigned(result);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/DirectStoreNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package org.graalvm.compiler.replacements.nodes;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
-
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.StateSplit;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.RawStoreNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Value;
-
-/**
- * A special purpose store node that differs from {@link RawStoreNode} in that it is not a
- * {@link StateSplit} and takes a computed address instead of an object.
- */
-@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
-public final class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
-
-    public static final NodeClass<DirectStoreNode> TYPE = NodeClass.create(DirectStoreNode.class);
-    @Input protected ValueNode address;
-    @Input protected ValueNode value;
-    protected final JavaKind kind;
-
-    public DirectStoreNode(ValueNode address, ValueNode value, JavaKind kind) {
-        super(TYPE, StampFactory.forVoid());
-        this.address = address;
-        this.value = value;
-        this.kind = kind;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        Value v = gen.operand(value);
-        LIRKind lirKind = LIRKind.fromJavaKind(gen.getLIRGeneratorTool().target().arch, kind);
-        gen.getLIRGeneratorTool().getArithmetic().emitStore(lirKind, gen.operand(address), v, null);
-    }
-
-    public ValueNode getAddress() {
-        return address;
-    }
-
-    public ValueNode getValue() {
-        return value;
-    }
-
-    @NodeIntrinsic
-    public static native void storeBoolean(long address, boolean value, @ConstantNodeParameter JavaKind kind);
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -49,6 +49,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
@@ -57,7 +58,6 @@
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
@@ -160,7 +160,7 @@
      */
     @SuppressWarnings("try")
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
-        final PhaseContext c = new PhaseContext(tool.getProviders());
+        final CoreProviders c = tool.getProviders();
         if (!graph().hasValueProxies()) {
             new RemoveValueProxyPhase().apply(replacementGraph);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java	Fri Jun 28 14:36:42 2019 +0530
@@ -206,7 +206,8 @@
                     StampPair returnStamp, ValueNode[] arguments) {
         ValueNode methodHandleNode = getReceiver(arguments);
         if (methodHandleNode.isConstant()) {
-            return getTargetInvokeNode(adder, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
+            return getTargetInvokeNode(adder, intrinsicMethod, methodHandleAccess, bci, returnStamp, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true),
+                            original);
         }
         return null;
     }
@@ -227,7 +228,7 @@
                     StampPair returnStamp, ValueNode[] arguments) {
         ValueNode memberNameNode = getMemberName(arguments);
         if (memberNameNode.isConstant()) {
-            return getTargetInvokeNode(adder, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
+            return getTargetInvokeNode(adder, intrinsicMethod, methodHandleAccess, bci, returnStamp, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
         }
         return null;
     }
@@ -241,9 +242,10 @@
      *
      * @return invoke node for the member name target
      */
-    private static InvokeNode getTargetInvokeNode(GraphAdder adder, IntrinsicMethod intrinsicMethod, int bci, StampPair returnStamp, ValueNode[] originalArguments, ResolvedJavaMethod target,
+    private static InvokeNode getTargetInvokeNode(GraphAdder adder, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, int bci, StampPair returnStamp,
+                    ValueNode[] originalArguments, ResolvedJavaMethod target,
                     ResolvedJavaMethod original) {
-        if (target == null) {
+        if (target == null || !isConsistentInfo(methodHandleAccess, original, target)) {
             return null;
         }
 
@@ -390,4 +392,84 @@
             return new InvokeNode(callTarget, bci);
         }
     }
+
+    /**
+     * Checks basic type consistency of low level method handle intrinsics.
+     *
+     * @param original declared method
+     * @param target resolved method
+     * @return true if original is type consistent with target
+     */
+    private static boolean isConsistentInfo(MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, ResolvedJavaMethod target) {
+        IntrinsicMethod originalIntrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(original);
+        assert originalIntrinsicMethod == IntrinsicMethod.INVOKE_BASIC ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_STATIC ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_SPECIAL ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE;
+        IntrinsicMethod targetIntrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(target);
+        Signature originalSignature = original.getSignature();
+        Signature targetSignature = target.getSignature();
+
+        boolean invokeThroughMHIntrinsic = originalIntrinsicMethod != null && targetIntrinsicMethod == null;
+        if (!invokeThroughMHIntrinsic) {
+            return (original.getName().equals(target.getName())) && (originalSignature.equals(targetSignature));
+        }
+
+        // Linkers have appendix argument which is not passed to callee.
+        int hasAppendix = (originalIntrinsicMethod == IntrinsicMethod.LINK_TO_STATIC ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_SPECIAL ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL ||
+                        originalIntrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) ? 1 : 0;
+        if (originalSignature.getParameterCount(original.hasReceiver()) != (targetSignature.getParameterCount(target.hasReceiver()) + hasAppendix)) {
+            return false; // parameter count mismatch
+        }
+        int senderBase = 0;
+        int receiverBase = 0;
+        switch (originalIntrinsicMethod) {
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+            case LINK_TO_SPECIAL: {
+                if (target.isStatic()) {
+                    return false;
+                }
+                if (originalSignature.getParameterKind(0).isPrimitive()) {
+                    return false; // receiver should be an oop
+                }
+                senderBase = 1; // skip receiver
+                break;
+            }
+            case LINK_TO_STATIC: {
+                if (target.hasReceiver()) {
+                    return false;
+                }
+                break;
+            }
+            case INVOKE_BASIC: {
+                if (target.isStatic()) {
+                    if (targetSignature.getParameterKind(0).isPrimitive()) {
+                        return false; // receiver should be an oop
+                    }
+                    receiverBase = 1; // skip receiver
+                }
+                break;
+            }
+            default:
+                break;
+        }
+        assert (targetSignature.getParameterCount(false) - receiverBase) == (originalSignature.getParameterCount(false) - senderBase - hasAppendix) : "argument count mismatch";
+        int argCount = targetSignature.getParameterCount(false) - receiverBase;
+        for (int i = 0; i < argCount; i++) {
+            if (originalSignature.getParameterKind(senderBase + i).getStackKind() != targetSignature.getParameterKind(receiverBase + i).getStackKind()) {
+                return false;
+            }
+        }
+        // Only check the return type if the symbolic info has non-void return type.
+        // I.e. the return value of the resolved method can be dropped.
+        if (originalSignature.getReturnKind() != JavaKind.Void &&
+                        originalSignature.getReturnKind().getStackKind() != targetSignature.getReturnKind().getStackKind()) {
+            return false;
+        }
+        return true; // no mismatch found
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/BufferUtil.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package org.graalvm.compiler.serviceprovider;
+
+import java.nio.Buffer;
+
+/**
+ * Covariant return types for some methods in the {@code java.nio.Buffer} were
+ * <a href="https://bugs.openjdk.java.net/browse/JDK-4774077">introduced in JDK 9</a>.
+ *
+ * If calls to these methods are compiled with javac from JDK 9+ using {@code -target 8 -source 8}
+ * then the call sites will invoke the covariant methods in the subclass. For example:
+ *
+ * <pre>
+ * static void reset(ByteBuffer buf) {
+ *     buf.reset();
+ * }
+ * </pre>
+ *
+ * will result in:
+ *
+ * <pre>
+ *    0: aload_0
+ *    1: invokevirtual #7  // Method java/nio/ByteBuffer.reset:()Ljava/nio/ByteBuffer;
+ *    4: pop
+ *    5: return
+ * </pre>
+ *
+ * This will result in a {@link NoSuchMethodError} when run on JDK 8. The workaround for this is to
+ * {@linkplain #asBaseBuffer(Buffer) coerce} the receiver for calls to the covariant methods to
+ * {@link Buffer}.
+ */
+public final class BufferUtil {
+
+    /**
+     * Coerces {@code obj} to be of type {@link Buffer}. This is required instead of a cast as
+     * {@code org.graalvm.compiler.core.test.VerifyBufferUsage} is based on Graal graphs which will
+     * have had redundant casts eliminated by the bytecode parser.
+     */
+    public static Buffer asBaseBuffer(Buffer obj) {
+        return obj;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Fri Jun 28 14:36:42 2019 +0530
@@ -89,7 +89,15 @@
             synchronized (servicesCache) {
                 ArrayList<S> providersList = new ArrayList<>();
                 for (S provider : providers) {
-                    providersList.add(provider);
+                    /*
+                     * When building libgraal, we want providers that comes from the Graal community
+                     * and enterprise modules but not those available on the native-image class
+                     * path.
+                     */
+                    Module module = provider.getClass().getModule();
+                    if (module.isNamed()) {
+                        providersList.add(provider);
+                    }
                 }
                 providers = providersList;
                 servicesCache.put(service, providersList);
@@ -101,7 +109,7 @@
     }
 
     protected static <S> Iterable<S> load0(Class<S> service) {
-        Iterable<S> iterable = ServiceLoader.load(service, GraalServices.class.getClassLoader());
+        Iterable<S> iterable = ServiceLoader.load(service);
         return new Iterable<>() {
             @Override
             public Iterator<S> iterator() {
@@ -136,7 +144,9 @@
      * @param other all JVMCI packages will be opened to the module defining this class
      */
     static void openJVMCITo(Class<?> other) {
-        if (IS_IN_NATIVE_IMAGE) return;
+        if (IS_IN_NATIVE_IMAGE) {
+            return;
+        }
 
         Module jvmciModule = JVMCI_MODULE;
         Module otherModule = other.getModule();
@@ -526,6 +536,6 @@
      * was produced as a result of a call to a {@code valueOf} method.
      */
     public static void markVirtualObjectAsAutoBox(VirtualObject virtualObject) {
-       virtualObject.setIsAutoBox(true);
+        virtualObject.setIsAutoBox(true);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JavaVersionUtil.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JavaVersionUtil.java	Fri Jun 28 14:36:42 2019 +0530
@@ -43,17 +43,7 @@
      * The integer value corresponding to the value of the {@code java.specification.version} system
      * property after any leading {@code "1."} has been stripped.
      */
-    public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
-
-    /**
-     * Determines if the Java runtime is version 8 or earlier.
-     */
-    public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
-
-    /**
-     * Determines if the Java runtime is version 11 or earlier.
-     */
-    public static final boolean Java11OrEarlier = JAVA_SPECIFICATION_VERSION <= 11;
+    public static final int JAVA_SPEC = getJavaSpecificationVersion();
 
     private JavaVersionUtil() {
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java	Fri Jun 28 14:36:42 2019 +0530
@@ -24,20 +24,22 @@
 
 package org.graalvm.compiler.test;
 
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
+
 /**
  * A class loader that exports all packages in the module defining the class loader to all classes
  * in the unnamed module associated with the loader.
  */
 public class ExportingClassLoader extends ClassLoader {
     public ExportingClassLoader() {
-        if (!GraalTest.Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             JLModule.fromClass(getClass()).exportAllPackagesTo(JLModule.getUnnamedModuleFor(this));
         }
     }
 
     public ExportingClassLoader(ClassLoader parent) {
         super(parent);
-        if (!GraalTest.Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
             JLModule.fromClass(getClass()).exportAllPackagesTo(JLModule.getUnnamedModuleFor(this));
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.debug.GlobalMetrics;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.serviceprovider.GraalServices;
-import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.AssumptionViolatedException;
@@ -73,9 +72,6 @@
         }
     }
 
-    public static final boolean Java8OrEarlier = JavaVersionUtil.Java8OrEarlier;
-    public static final boolean Java11OrEarlier = JavaVersionUtil.Java11OrEarlier;
-
     protected Method getMethod(String methodName) {
         return getMethod(getClass(), methodName);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,6 +28,8 @@
 import java.lang.reflect.Method;
 import java.util.Set;
 
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
+
 /**
  * Facade for the {@code java.lang.Module} class introduced in JDK9 that allows tests to be
  * developed against JDK8 but use module logic if deployed on JDK9.
@@ -35,7 +37,7 @@
 public class JLModule {
 
     static {
-        if (GraalTest.Java8OrEarlier) {
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
             throw new AssertionError("Use of " + JLModule.class + " only allowed if " + GraalTest.class.getName() + ".JDK8OrEarlier is false");
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Fri Jun 28 14:36:42 2019 +0530
@@ -249,7 +249,7 @@
         return new Subprocess(command, process.waitFor(), output);
     }
 
-    private static final boolean isJava8OrEarlier = JavaVersionUtil.Java8OrEarlier;
+    private static final boolean isJava8OrEarlier = JavaVersionUtil.JAVA_SPEC <= 8;
 
     private static boolean hasArg(String optionName) {
         if (optionName.equals("-cp") || optionName.equals("-classpath")) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EarlyReadEliminationPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EarlyReadEliminationPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -29,10 +29,10 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
+public class EarlyReadEliminationPhase extends EffectsPhase<CoreProviders> {
 
     private final boolean considerGuards;
 
@@ -47,14 +47,14 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue(graph.getOptions()))) {
             runAnalysis(graph, context);
         }
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
+    protected Closure<?> createEffectsClosure(CoreProviders context, ScheduleResult schedule, ControlFlowGraph cfg) {
         assert schedule == null;
         return new ReadEliminationClosure(cfg, considerGuards);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -31,19 +31,18 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public abstract class EffectsPhase<PhaseContextT extends PhaseContext> extends BasePhase<PhaseContextT> {
+public abstract class EffectsPhase<CoreProvidersT extends CoreProviders> extends BasePhase<CoreProvidersT> {
 
     public abstract static class Closure<T> extends ReentrantBlockIterator.BlockIteratorClosure<T> {
 
@@ -69,12 +68,12 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContextT context) {
+    protected void run(StructuredGraph graph, CoreProvidersT context) {
         runAnalysis(graph, context);
     }
 
     @SuppressWarnings("try")
-    public boolean runAnalysis(StructuredGraph graph, PhaseContextT context) {
+    public boolean runAnalysis(StructuredGraph graph, CoreProvidersT context) {
         boolean changed = false;
         CompilationAlarm compilationAlarm = CompilationAlarm.current();
         DebugContext debug = graph.getDebug();
@@ -99,21 +98,15 @@
                         EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener();
                         try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
                             closure.applyEffects();
-                        }
 
-                        if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) {
-                            debug.dump(DebugContext.VERBOSE_LEVEL, graph, "%s iteration", getName());
+                            if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) {
+                                debug.dump(DebugContext.VERBOSE_LEVEL, graph, "%s iteration", getName());
+                            }
+
+                            new DeadCodeEliminationPhase(Required).apply(graph);
                         }
 
-                        new DeadCodeEliminationPhase(Required).apply(graph);
-
-                        EconomicSet<Node> changedNodes = listener.getNodes();
-                        for (Node node : graph.getNodes()) {
-                            if (node instanceof Simplifiable) {
-                                changedNodes.add(node);
-                            }
-                        }
-                        postIteration(graph, context, changedNodes);
+                        postIteration(graph, context, listener.getNodes());
                     }
 
                     if (closure.hasChanged()) {
@@ -129,11 +122,11 @@
         return changed;
     }
 
-    protected void postIteration(final StructuredGraph graph, final PhaseContextT context, EconomicSet<Node> changedNodes) {
+    protected void postIteration(final StructuredGraph graph, final CoreProvidersT context, EconomicSet<Node> changedNodes) {
         if (canonicalizer != null) {
             canonicalizer.applyIncremental(graph, context, changedNodes);
         }
     }
 
-    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, ScheduleResult schedule, ControlFlowGraph cfg);
+    protected abstract Closure<?> createEffectsClosure(CoreProvidersT context, ScheduleResult schedule, ControlFlowGraph cfg);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/GraphEffectList.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/GraphEffectList.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.ControlSinkNode;
@@ -196,11 +197,14 @@
 
     public void replaceWithSink(FixedWithNextNode node, ControlSinkNode sink) {
         add("kill if branch", new Effect() {
+            @SuppressWarnings("try")
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
-                graph.addWithoutUnique(sink);
-                node.replaceAtPredecessor(sink);
-                GraphUtil.killCFG(node);
+                try (DebugCloseable position = graph.withNodeSourcePosition(node)) {
+                    graph.addWithoutUnique(sink);
+                    node.replaceAtPredecessor(sink);
+                    GraphUtil.killCFG(node);
+                }
             }
 
             @Override
@@ -221,33 +225,36 @@
      * @param insertBefore
      *
      */
+    @SuppressWarnings("try")
     public void replaceAtUsages(ValueNode node, ValueNode replacement, FixedNode insertBefore) {
         assert node != null && replacement != null : node + " " + replacement;
         assert !node.hasUsages() || node.stamp(NodeView.DEFAULT).isCompatible(replacement.stamp(NodeView.DEFAULT)) : "Replacement node stamp not compatible " + node.stamp(NodeView.DEFAULT) + " vs " +
                         replacement.stamp(NodeView.DEFAULT);
         add("replace at usages", (graph, obsoleteNodes) -> {
-            assert node.isAlive();
-            ValueNode replacementNode = graph.addOrUniqueWithInputs(replacement);
-            assert replacementNode.isAlive();
-            assert insertBefore != null;
-            if (replacementNode instanceof FixedWithNextNode && ((FixedWithNextNode) replacementNode).next() == null) {
-                graph.addBeforeFixed(insertBefore, (FixedWithNextNode) replacementNode);
+            try (DebugCloseable position = graph.withNodeSourcePosition(node)) {
+                assert node.isAlive();
+                ValueNode replacementNode = graph.addOrUniqueWithInputs(replacement);
+                assert replacementNode.isAlive();
+                assert insertBefore != null;
+                if (replacementNode instanceof FixedWithNextNode && ((FixedWithNextNode) replacementNode).next() == null) {
+                    graph.addBeforeFixed(insertBefore, (FixedWithNextNode) replacementNode);
+                }
+                /*
+                 * Keep the (better) stamp information when replacing a node with another one if the
+                 * replacement has a less precise stamp than the original node. This can happen for
+                 * example in the context of read nodes and unguarded pi nodes where the pi will be
+                 * used to improve the stamp information of the read. Such a read might later be
+                 * replaced with a read with a less precise stamp.
+                 */
+                if (node.hasUsages() && !node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) {
+                    replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT)));
+                }
+                node.replaceAtUsages(replacementNode);
+                if (node instanceof FixedWithNextNode) {
+                    GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+                }
+                obsoleteNodes.add(node);
             }
-            /*
-             * Keep the (better) stamp information when replacing a node with another one if the
-             * replacement has a less precise stamp than the original node. This can happen for
-             * example in the context of read nodes and unguarded pi nodes where the pi will be used
-             * to improve the stamp information of the read. Such a read might later be replaced
-             * with a read with a less precise stamp.
-             */
-            if (node.hasUsages() && !node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) {
-                replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT)));
-            }
-            node.replaceAtUsages(replacementNode);
-            if (node instanceof FixedWithNextNode) {
-                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
-            }
-            obsoleteNodes.add(node);
         });
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java	Fri Jun 28 14:36:42 2019 +0530
@@ -32,6 +32,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -39,9 +40,8 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
 
-public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
+public class PartialEscapePhase extends EffectsPhase<CoreProviders> {
 
     static class Options {
         //@formatter:off
@@ -51,24 +51,24 @@
     }
 
     private final boolean readElimination;
-    private final BasePhase<PhaseContext> cleanupPhase;
+    private final BasePhase<CoreProviders> cleanupPhase;
 
     public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, OptionValues options) {
         this(iterative, Options.OptEarlyReadElimination.getValue(options), canonicalizer, null, options);
     }
 
-    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase, OptionValues options) {
+    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, BasePhase<CoreProviders> cleanupPhase, OptionValues options) {
         this(iterative, Options.OptEarlyReadElimination.getValue(options), canonicalizer, cleanupPhase, options);
     }
 
-    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer, BasePhase<PhaseContext> cleanupPhase, OptionValues options) {
+    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer, BasePhase<CoreProviders> cleanupPhase, OptionValues options) {
         super(iterative ? EscapeAnalysisIterations.getValue(options) : 1, canonicalizer);
         this.readElimination = readElimination;
         this.cleanupPhase = cleanupPhase;
     }
 
     @Override
-    protected void postIteration(StructuredGraph graph, PhaseContext context, EconomicSet<Node> changedNodes) {
+    protected void postIteration(StructuredGraph graph, CoreProviders context, EconomicSet<Node> changedNodes) {
         super.postIteration(graph, context, changedNodes);
         if (cleanupPhase != null) {
             cleanupPhase.apply(graph, context);
@@ -76,7 +76,7 @@
     }
 
     @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
+    protected void run(StructuredGraph graph, CoreProviders context) {
         if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue(graph.getOptions()))) {
             if (readElimination || graph.hasVirtualizableAllocation()) {
                 runAnalysis(graph, context);
@@ -85,7 +85,7 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
+    protected Closure<?> createEffectsClosure(CoreProviders context, ScheduleResult schedule, ControlFlowGraph cfg) {
         for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) {
             virtual.resetObjectId();
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java	Fri Jun 28 14:36:42 2019 +0530
@@ -38,7 +38,7 @@
  *
  * @param <G> the type of graph this instance handles
  * @param <M> the type of methods this instance handles
- * @since 1.0 a {@link WritableByteChannel} is implemented
+ * @since 19.0 a {@link WritableByteChannel} is implemented
  */
 public final class GraphOutput<G, M> implements Closeable, WritableByteChannel {
     private final GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?, ?> printer;
@@ -112,7 +112,7 @@
      * Checks if the {@link GraphOutput} is open.
      *
      * @return true if the {@link GraphOutput} is open.
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     public boolean isOpen() {
@@ -125,7 +125,7 @@
      * @param src the bytes to write
      * @return the number of bytes written, possibly zero
      * @throws IOException in case of IO error
-     * @since 1.0
+     * @since 19.0
      */
     @Override
     public int write(ByteBuffer src) throws IOException {
@@ -178,7 +178,7 @@
          *
          * @param embedded if {@code true} the builder creates an embedded {@link GraphOutput}
          * @return this builder
-         * @since 1.0
+         * @since 19.0
          */
         public Builder<G, N, M> embedded(boolean embedded) {
             this.embeddedGraphOutput = embedded;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.channels.WritableByteChannel;
 import java.nio.charset.Charset;
@@ -86,6 +87,13 @@
     final int versionMinor;
     private boolean printing;
 
+    /**
+     * See {@code org.graalvm.compiler.serviceprovider.BufferUtil}.
+     */
+    private static Buffer asBaseBuffer(Buffer obj) {
+        return obj;
+    }
+
     GraphProtocol(WritableByteChannel channel, int major, int minor, boolean embedded) throws IOException {
         if (major > MAJOR_VERSION || (major == MAJOR_VERSION && minor > MINOR_VERSION)) {
             throw new IllegalArgumentException("Unrecognized version " + major + "." + minor);
@@ -328,7 +336,7 @@
     }
 
     private void flush() throws IOException {
-        buffer.flip();
+        asBaseBuffer(buffer).flip();
         /*
          * Try not to let interrupted threads abort the write. There's still a race here but an
          * interrupt that's been pending for a long time shouldn't stop this writing.
@@ -411,12 +419,12 @@
         while (b.position() < limit) {
             int toWrite = Math.min(limit - b.position(), buffer.capacity());
             ensureAvailable(toWrite);
-            b.limit(b.position() + toWrite);
+            asBaseBuffer(b).limit(b.position() + toWrite);
             try {
                 buffer.put(b);
                 written += toWrite;
             } finally {
-                b.limit(limit);
+                asBaseBuffer(b).limit(limit);
             }
         }
         return written;
@@ -430,7 +438,7 @@
             int sizeInBytes = b.length * 4;
             ensureAvailable(sizeInBytes);
             buffer.asIntBuffer().put(b);
-            buffer.position(buffer.position() + sizeInBytes);
+            asBaseBuffer(buffer).position(buffer.position() + sizeInBytes);
         }
     }
 
@@ -442,7 +450,7 @@
             int sizeInBytes = b.length * 8;
             ensureAvailable(sizeInBytes);
             buffer.asDoubleBuffer().put(b);
-            buffer.position(buffer.position() + sizeInBytes);
+            asBaseBuffer(buffer).position(buffer.position() + sizeInBytes);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java	Fri Jun 28 14:36:42 2019 +0530
@@ -61,8 +61,8 @@
  * <a href="doc-files/diamond.bgv">diamond.bgv</a> file generated from the above diamond structure
  * graph.
  * <p>
- * The primary <b>IGV</b> focus is on graphs used by Graal compiler. As such they aren't plain
- * graphs, but contain various compiler oriented attributes:
+ * The primary <b>IGV</b> focus is on graphs used by the compiler. As such they aren't plain graphs,
+ * but contain various compiler oriented attributes:
  * <ul>
  * <li>{@linkplain org.graalvm.graphio.GraphBlocks code blocks} information</li>
  * <li>{@linkplain org.graalvm.graphio.GraphElements method and fields} information</li>
@@ -80,7 +80,7 @@
  * <a href="http://wiki.apidesign.org/wiki/Singletonizer">singletonizer</a> API pattern again - e.g.
  * no need to change your existing data structures, just implement the operations provided by the
  * interfaces you pass into the builder. By combining these interfaces together you can get as rich,
- * colorful, source linked graphs as Graal compiler produces to describe its optimizations.
+ * colorful, source linked graphs as the compiler produces to describe its optimizations.
  */
 
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -28,7 +28,7 @@
 
 import jdk.internal.vm.compiler.collections.EconomicMap;
 import jdk.internal.vm.compiler.collections.Equivalence;
-import org.graalvm.compiler.test.GraalTest;
+import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.util.ObjectSizeEstimate;
 import org.junit.Assume;
 import org.junit.Test;
@@ -40,7 +40,7 @@
      */
     @Test
     public void testSize() {
-        Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier);
+        Assume.assumeTrue("Not working in JDK9 due to module visibility.", JavaVersionUtil.JAVA_SPEC <= 8);
         EconomicMap<Object, Object> map = EconomicMap.create(Equivalence.IDENTITY);
         assertEquals(49, ObjectSizeEstimate.forObject(map).getTotalBytes());
 
@@ -59,7 +59,7 @@
      */
     @Test
     public void testCompress() {
-        Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier);
+        Assume.assumeTrue("Not working in JDK9 due to module visibility.", JavaVersionUtil.JAVA_SPEC <= 8);
         EconomicMap<Object, Object> map = EconomicMap.create();
 
         // Measuring size of map with one entry.
--- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c	Wed Jun 26 14:28:47 2019 +0530
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -873,7 +873,6 @@
  "launch=<command line>            run debugger on event             none\n"
  "onthrow=<exception name>         debug on throw                    none\n"
  "onuncaught=y|n                   debug on any uncaught?            n\n"
- "onjcmd=y|n                       start debug via jcmd?             n\n"
  "timeout=<timeout value>          for listen/attach in milliseconds n\n"
  "mutf8=y|n                        output modified utf-8             n\n"
  "quiet=y|n                        control over terminal messages    n\n"));
--- a/test/hotspot/jtreg/TEST.groups	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/hotspot/jtreg/TEST.groups	Fri Jun 28 14:36:42 2019 +0530
@@ -275,6 +275,7 @@
  -runtime/ErrorHandling/ErrorHandler.java \
  -runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java \
  -runtime/ErrorHandling/TimeoutInErrorHandlingTest.java \
+ -runtime/InvocationTests \
  -runtime/logging/MonitorMismatchTest.java \
  -runtime/memory/ReserveMemory.java \
  -runtime/memory/RunUnitTestsConcurrently.java \
@@ -384,6 +385,7 @@
   serviceability/ \
  -runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java \
  -runtime/CompressedOops/UseCompressedOops.java \
+ -runtime/InvocationTests \
  -runtime/Thread/TestThreadDumpMonitorContention.java \
  -:tier1_runtime \
  -:tier1_serviceability \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/arguments/TestMaxRAMFlags.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package gc.arguments;
+
+/*
+ * @test TestMaxRAMFlags
+ * @key gc
+ * @bug 8222252
+ * @summary Verify correct MaxHeapSize and UseCompressedOops when MaxRAM and MaxRAMPercentage
+ * are specified.
+ * @library /test/lib
+ * @library /
+ * @requires vm.bits == "64"
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main gc.arguments.TestMaxRAMFlags
+ * @author bob.vandette@oracle.com
+ */
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class TestMaxRAMFlags {
+
+  private static void checkMaxRAMSize(long maxram, int maxrampercent, boolean forcecoop, long expectheap, boolean expectcoop) throws Exception {
+
+    ArrayList<String> args = new ArrayList<String>();
+    args.add("-XX:MaxRAM=" + maxram);
+    args.add("-XX:MaxRAMPercentage=" + maxrampercent);
+    if (forcecoop) {
+      args.add("-XX:+UseCompressedOops");
+    }
+
+    args.add("-XX:+PrintFlagsFinal");
+    args.add("-version");
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[0]));
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+    output.shouldHaveExitValue(0);
+    String stdout = output.getStdout();
+
+    long actualheap = new Long(getFlagValue("MaxHeapSize", stdout)).longValue();
+    if (actualheap != expectheap) {
+      throw new RuntimeException("MaxHeapSize value set to " + actualheap +
+        ", expected " + expectheap + " when running with the following flags: " + Arrays.asList(args).toString());
+    }
+
+    boolean actualcoop = getFlagBoolValue("UseCompressedOops", stdout);
+    if (actualcoop != expectcoop) {
+      throw new RuntimeException("UseCompressedOops set to " + actualcoop +
+        ", expected " + expectcoop + " when running with the following flags: " + Arrays.asList(args).toString());
+    }
+  }
+
+  private static long getHeapBaseMinAddress() throws Exception {
+    ArrayList<String> args = new ArrayList<String>();
+    args.add("-XX:+PrintFlagsFinal");
+    args.add("-version");
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[0]));
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+    output.shouldHaveExitValue(0);
+    String stdout = output.getStdout();
+    return (new Long(getFlagValue("HeapBaseMinAddress", stdout)).longValue());
+  }
+
+  private static String getFlagValue(String flag, String where) {
+    Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where);
+    if (!m.find()) {
+      throw new RuntimeException("Could not find value for flag " + flag + " in output string");
+    }
+    String match = m.group();
+    return match.substring(match.lastIndexOf(" ") + 1, match.length());
+  }
+
+  private static boolean getFlagBoolValue(String flag, String where) {
+    Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where);
+    if (!m.find()) {
+      throw new RuntimeException("Could not find value for flag " + flag + " in output string");
+    }
+    return m.group(1).equals("true");
+  }
+
+  public static void main(String args[]) throws Exception {
+    // Tests
+    // 1. Verify that MaxRAMPercentage overrides UseCompressedOops Ergo
+    // 2. Verify that UseCompressedOops forces compressed oops limit even
+    //    when other flags are specified.
+
+    long oneG = 1L * 1024L * 1024L * 1024L;
+
+    // Hotspot startup logic reduces MaxHeapForCompressedOops by HeapBaseMinAddress
+    // in order to get zero based compressed oops offsets.
+    long heapbaseminaddr = getHeapBaseMinAddress();
+    long maxcoopheap = TestUseCompressedOopsErgoTools.getMaxHeapForCompressedOops(new String [0]) - heapbaseminaddr;
+
+    // Args: MaxRAM , MaxRAMPercentage, forcecoop, expect heap, expect coop
+    checkMaxRAMSize(maxcoopheap - oneG, 100, false, maxcoopheap - oneG, true);
+    checkMaxRAMSize(maxcoopheap + oneG, 100, false, maxcoopheap + oneG, false);
+    checkMaxRAMSize(maxcoopheap + oneG, 100, true, maxcoopheap, true);
+  }
+}
--- a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java	Fri Jun 28 14:36:42 2019 +0530
@@ -95,21 +95,28 @@
         new LogMessageWithLevel("Post Evacuate Collection Set", Level.INFO),
         new LogMessageWithLevel("Other", Level.INFO),
 
-        // Update RS
-        new LogMessageWithLevel("Update RS", Level.DEBUG),
+        // Merge Heap Roots
+        new LogMessageWithLevel("Merge Heap Roots", Level.INFO),
+        new LogMessageWithLevel("Remembered Sets", Level.DEBUG),
+        new LogMessageWithLevel("Merged Sparse", Level.DEBUG),
+        new LogMessageWithLevel("Merged Fine", Level.DEBUG),
+        new LogMessageWithLevel("Merged Coarse", Level.DEBUG),
+        new LogMessageWithLevel("Hot Card Cache", Level.DEBUG),
+        new LogMessageWithLevel("Log Buffers", Level.DEBUG),
         new LogMessageWithLevel("Processed Buffers", Level.DEBUG),
-        new LogMessageWithLevel("Scanned Cards", Level.DEBUG),
+        new LogMessageWithLevel("Dirty Cards", Level.DEBUG),
         new LogMessageWithLevel("Skipped Cards", Level.DEBUG),
-        new LogMessageWithLevel("Scan HCC", Level.DEBUG),
-        // Scan RS
-        new LogMessageWithLevel("Scan RS", Level.DEBUG),
+        // Scan Heap Roots
+        new LogMessageWithLevel("Scan Heap Roots", Level.DEBUG),
         new LogMessageWithLevel("Scanned Cards", Level.DEBUG),
-        new LogMessageWithLevel("Claimed Cards", Level.DEBUG),
-        new LogMessageWithLevel("Skipped Cards", Level.DEBUG),
+        new LogMessageWithLevel("Scanned Blocks", Level.DEBUG),
+        new LogMessageWithLevel("Claimed Chunks", Level.DEBUG),
+        // Code Roots Scan
+        new LogMessageWithLevel("Code Root Scan", Level.DEBUG),
         // Object Copy
         new LogMessageWithLevel("Object Copy", Level.DEBUG),
-        new LogMessageWithLevel("Scanned Cards", Level.DEBUG),
-        new LogMessageWithLevel("Claimed Cards", Level.DEBUG),
+        new LogMessageWithLevel("LAB Waste", Level.DEBUG),
+        new LogMessageWithLevel("LAB Undo Waste", Level.DEBUG),
         // Ext Root Scan
         new LogMessageWithLevel("Thread Roots", Level.TRACE),
         new LogMessageWithLevel("Universe Roots", Level.TRACE),
@@ -133,6 +140,7 @@
         new LogMessageWithLevel("Table Fixup", Level.DEBUG),
         new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
         new LogMessageWithLevel("Region Register", Level.DEBUG),
+        new LogMessageWithLevel("Prepare Heap Roots", Level.DEBUG),
         // Free CSet
         new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
         new LogMessageWithLevel("Free Collection Set Serial", Level.TRACE),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterface/Checker.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokeinterface;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class Checker extends shared.Checker {
+    private Class interfaceClass;
+
+    public Checker(Class interfaceClass, Class dynamicTargetClass) {
+        super(interfaceClass, dynamicTargetClass);
+
+        if (staticTargetClass.isInterface()) {
+            this.interfaceClass = staticTargetClass;
+        } else {
+            throw new RuntimeException("Static target class should be an interface.");
+        }
+    }
+
+    public String check (Class callerClass) {
+        // Check access rights to interface for caller
+        if (!checkAccess(interfaceClass, callerClass)) {
+            return "java.lang.IllegalAccessError";
+        }
+
+        // NSME is thrown when interface doesn't declare the method
+        if (getDeclaredMethod(interfaceClass) == null) {
+            return "java.lang.NoSuchMethodError";
+        }
+
+        // 9.1.5 Access to Interface Member Names
+        // "All interface members are implicitly public. They are
+        // accessible outside the package where the interface is
+        // declared if the interface is also declared public or
+        // protected, in accordance with the rules of 6.6."
+
+        // Search for method declaration in the hierarchy
+        Class klass = dynamicTargetClass;
+
+        while (klass != Object.class) {
+            Method method = getDeclaredMethod(klass);
+
+            if (method != null) {
+                int modifiers = method.getModifiers();
+
+                // Check whether obtained method is public and isn't abstract
+                if ( Modifier.isPublic(modifiers))
+                {
+                    if (Modifier.isAbstract(modifiers)) {
+                        return "java.lang.AbstractMethodError";
+                    } else {
+                        return String.format("%s.%s"
+                            , method.getDeclaringClass().getSimpleName()
+                            , methodName
+                            );
+                    }
+                } else {
+                    // IAE is thrown when located method isn't PUBLIC
+                    // or private.  Private methods are skipped when
+                    // looking for an interface method.
+                    if (!Modifier.isPrivate(modifiers)) {
+                        return "java.lang.IllegalAccessError";
+                    }
+                }
+            }
+
+            klass = klass.getSuperclass();
+        }
+
+        // No method declaration is found
+        return "java.lang.AbstractMethodError";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterface/ClassGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokeinterface;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import shared.GenericClassGenerator;
+
+/*******************************************************************/
+class ClassGenerator extends GenericClassGenerator<ClassGenerator> {
+    public ClassGenerator(String fullClassName) {
+        super(fullClassName);
+    }
+
+    public ClassGenerator(String fullClassName, String parentClassName) {
+        super(fullClassName, parentClassName);
+    }
+
+    public ClassGenerator(String fullClassName, String parentClassName, int flags) {
+        super(fullClassName, parentClassName, flags);
+    }
+
+    public ClassGenerator(String fullClassName, String parentClassName, int flags, String[] implementedInterfaces) {
+        super(fullClassName, parentClassName, flags, implementedInterfaces);
+    }
+
+    // Add target method call site into current class
+    public ClassGenerator addCaller(String targetClass) {
+        return super.addCaller(targetClass, Opcodes.INVOKEINTERFACE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterface/Generator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * INVOKE_INTERFACE EXPECTED RESULTS
+ *
+ * Let C be the class of objectref. The actual method to be invoked is selected
+ * by the following lookup procedure:
+ *     - If C contains a declaration for an instance method with the same name
+ *     and descriptor as the resolved method, then this is the method to be
+ *     invoked, and the lookup procedure terminates.
+ *
+ *     - Otherwise, if C has a superclass, this same lookup procedure is
+ *     performed recursively using the direct superclass of C; the method to be
+ *     invoked is the result of the recursive invocation of this lookup
+ *     procedure.
+ *
+ * Otherwise, if the class of objectref does not implement the resolved
+ * interface, invokeinterface throws an IncompatibleClassChangeError?.
+ *
+ * Otherwise, if no method matching the resolved name and descriptor is
+ * selected, invokeinterface throws an AbstractMethodError?.
+ *
+ * Otherwise, if the selected method is not public, invokeinterface throws an
+ * IllegalAccessError. Note that it cannot be private because private methods
+ * are ignored when searching for an interface method.
+ *
+ * My translation:
+ *      1. Resolve compile-time class/method.
+ *      2. Look up runtime class C, if it contains a name/signature match,
+ *      and it is not private, invoke it.
+ *      3. If it does not, recursively lookup direct superclass of C.
+ *      4. If selected method is not public, throw IllegalAccessError
+ *
+ * InvokeInterface Results:
+ *    - A interface class, declares A.m
+ *    - A compile-time resolved class
+ *    - C runtime resolved class
+ *    - InvokeInterface will ALWAYS invoke C.m if C.m exists and is not private,
+ *    regardless of overriding or accessibility
+ *    - InvokeInterface will invoke a non-private B.m if C.m does not exist,
+ *    regardless of overriding or accessibility
+ *
+ * Note: assuming Interface is public
+ *
+ * TODO: member interfaces can be protected and private and have special hiding
+ * rules (JLS 8.5)
+ */
+
+package invokeinterface;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import shared.AbstractGenerator;
+import shared.AccessType;
+import shared.Utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Generator extends AbstractGenerator {
+    public Generator(String[] args) {
+        super(args);
+    }
+
+    protected Checker getChecker(Class paramClass, Class targetClass) {
+        return new Checker(paramClass, targetClass);
+    }
+
+    public static void main (String[] args) throws Exception {
+        new Generator(args).run();
+    }
+
+    private void run() throws Exception {
+        // Specify package names
+        String pkg1 = "a.";
+        String pkg2 = "b.";
+        String pkg3 = "c.";
+        String pkgIntf = "i.";
+        String[] packages = new String[] { "", pkg1, pkg2, pkg3, pkgIntf };
+
+        int testNum = 0;
+        boolean isPassed = true;
+
+        // Hierarchy
+        // The following triples will be used during further
+        // hierarchy construction and will specify packages for A, B and C
+        String[][] packageSets = new String[][] {
+              {   "",   "",   "", ""}
+            , {   "",   "",   "", pkgIntf }
+
+            , {   "", pkg1, pkg1, "" }
+            , {   "", pkg1, pkg1, pkg1 }
+            , {   "", pkg1, pkg1, pkgIntf }
+
+            , {   "", pkg1, pkg2, "" }
+            , {   "", pkg1, pkg2, pkg1}
+            , {   "", pkg1, pkg2, pkg2}
+            , {   "", pkg1, pkg2, pkgIntf}
+
+            , { pkg1, pkg1, pkg1, pkg1 }
+            , { pkg1, pkg1, pkg1, pkgIntf }
+
+            , { pkg1, pkg1, pkg2, pkg1 }
+            , { pkg1, pkg1, pkg2, pkg2 }
+            , { pkg1, pkg1, pkg2, pkgIntf }
+
+            , { pkg1, pkg2, pkg1, pkg1 }
+            , { pkg1, pkg2, pkg1, pkg2 }
+            , { pkg1, pkg2, pkg1, pkgIntf }
+
+            , { pkg1, pkg2, pkg2, pkg1 }
+            , { pkg1, pkg2, pkg2, pkg2 }
+            , { pkg1, pkg2, pkg2, pkgIntf }
+        };
+
+        String [] header = new String[] {
+            String.format("%30s %68s %25s", "Method access modifiers", "Call site location", "Status")
+                , String.format("%5s  %-12s %-12s %-12s %-12s   %7s %7s %7s %7s %7s %7s %7s"
+                        , "  # "
+                        , "A.m()"
+                        , "B.m()"
+                        , "C.m()"
+                        , "I.m()"
+                        , "  C  "
+                        , "pkgC "
+                        , "  B  "
+                        , " pkgB"
+                        , "  A  "
+                        , "pkgA"
+                        , "Intf"
+                        )
+                , "--------------------------------------------------------------------------------------------------------------------"
+        };
+
+        for (String aHeader : header) {
+            System.out.println(aHeader);
+        }
+
+        for (String[] pkgSet : packageSets) {
+            String packageA = pkgSet[0];
+            String packageB = pkgSet[1];
+            String packageC = pkgSet[2];
+
+            String packageIntf = pkgSet[3];
+
+            String classNameA = packageA + "A";
+            String classNameB = packageB + "B";
+            String classNameC = packageC + "C";
+            String classNameIntf = packageIntf + "I";
+
+            // For all possible access modifier combinations
+            for (AccessType accessA : AccessType.values()) {
+                for (AccessType accessB : AccessType.values()) {
+                    for (AccessType accessC : AccessType.values()) {
+                        for (AccessType accessIntf : AccessType.values()) {
+
+                            if (accessIntf == AccessType.UNDEF) {
+                                continue;
+                            }
+
+                            for (int I = 0; I < 4; I++) {
+                                boolean isAbstractA = ((I & 1) != 0);
+                                boolean isAbstractB = ((I & 2) != 0);
+
+                                testNum++;
+
+                                Map<String, byte[]> classes = new HashMap<String, byte[]>();
+
+                                // TODO: add non-PUBLIC interfaces, then particular call sites will affect the results
+
+                                // Generate interface Intf
+                                classes.put(
+                                        classNameIntf
+                                        , new ClassGenerator( classNameIntf
+                                                            , "java.lang.Object"
+                                                            , ACC_ABSTRACT | ACC_INTERFACE | accessIntf.value())
+                                            .addTargetMethod(AccessType.PUBLIC)
+                                            .getClassFile()
+                                        );
+
+                                // Generate class A
+                                classes.put(
+                                        classNameA
+                                        , new ClassGenerator( classNameA
+                                                            , "java.lang.Object"
+                                                            , ACC_PUBLIC | ( isAbstractA ? ACC_ABSTRACT : 0))
+                                            .addTargetMethod(accessA)
+                                            .addCaller(classNameIntf)
+                                            .getClassFile()
+                                        );
+
+                                // Generate class B
+                                classes.put(
+                                        classNameB
+                                        , new ClassGenerator( classNameB
+                                                            , classNameA
+                                                            , ACC_PUBLIC | ( isAbstractB ? ACC_ABSTRACT : 0)
+                                                            , new String[] { Utils.getInternalName(classNameIntf) })
+                                            .addTargetMethod(accessB)
+                                            .addCaller(classNameIntf)
+                                            .getClassFile()
+                                        );
+
+                                // Generate class C
+                                classes.put( classNameC
+                                           , new ClassGenerator( classNameC, classNameB )
+                                               .addTargetMethod(accessC)
+                                               .addCaller(classNameIntf)
+                                               .getClassFile()
+                                           );
+
+                                // Generate package callers
+                                for (String pkg : packages) {
+                                    classes.put( pkg+"Caller"
+                                               , new ClassGenerator(pkg+"Caller")
+                                                   .addCaller(classNameIntf)
+                                                   .getClassFile()
+                                               );
+                                }
+
+                                String caseDescription =
+                                        String.format("%-12s %-12s %-12s %-12s| "
+                                            , (isAbstractA ? "! " : "  ") + classNameA + " " + accessA
+                                            , (isAbstractB ? "! " : "  ") + classNameB + " " + accessB
+                                            , classNameC + " " + accessC
+                                            , accessIntf + " " + classNameIntf
+                                            );
+
+                                String[] callSites = new String[] {
+                                        classNameC
+                                        , packageC+"Caller"
+                                        , classNameB
+                                        , packageB+"Caller"
+                                        , classNameA
+                                        , packageA+"Caller"
+                                        , packageIntf+"Caller"
+                                };
+
+                                boolean result = exec(classes, caseDescription, classNameIntf, classNameC, callSites);
+                                isPassed = isPassed && result;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Print footer
+
+        for (int i = header.length-1; i >= 0; i--) {
+            System.out.println(header[i]);
+        }
+
+        if (executeTests) {
+            System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokeinterfaceTests.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8224137
+ * @summary Run invokeinterface invocation tests
+ * @library /test/lib
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @compile shared/AbstractGenerator.java shared/AccessCheck.java shared/AccessType.java
+ *          shared/Caller.java shared/ExecutorGenerator.java shared/Utils.java
+ *          shared/ByteArrayClassLoader.java shared/Checker.java shared/GenericClassGenerator.java
+ * @compile invokeinterface/Checker.java invokeinterface/ClassGenerator.java
+ *          invokeinterface/Generator.java
+ *
+ * @run main/othervm/timeout=1800 invokeinterfaceTests
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class invokeinterfaceTests {
+
+    public static void runTest(String classFileVersion, String option) throws Exception {
+        System.out.println("\ninvokeinterface invocation tests, option: " + option +
+                           ", class file version: " + classFileVersion);
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false, "-Xmx128M", option,
+            "invokeinterface.Generator", "--classfile_version=" + classFileVersion);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        try {
+            output.shouldContain("EXECUTION STATUS: PASSED");
+            output.shouldHaveExitValue(0);
+        } catch (Throwable e) {
+            System.out.println(
+                "\nNote that an entry such as 'B.m/C.m' in the failure chart means that" +
+                " the test case failed because method B.m was invoked but the test " +
+                "expected method C.m to be invoked. Similarly, a result such as 'AME/C.m'" +
+                " means that an AbstractMethodError exception was thrown but the test" +
+                " case expected method C.m to be invoked.");
+            System.out.println(
+                "\nAlso note that passing --dump to invokeinterface.Generator will" +
+                " dump the generated classes (for debugging purposes).\n");
+
+            System.exit(1);
+        }
+    }
+
+    public static void main(String args[]) throws Throwable {
+        // Get current major class file version and test with it.
+        byte klassbuf[] = InMemoryJavaCompiler.compile("blah", "public class blah { }");
+        int major_version = klassbuf[6] << 8 | klassbuf[7];
+        runTest(String.valueOf(major_version), "-Xint");
+        runTest(String.valueOf(major_version), "-Xcomp");
+
+        // Test old class file version.
+        runTest("51", "-Xint"); // JDK-7
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokespecial/Checker.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokespecial;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class Checker extends shared.Checker {
+
+    public Checker(Class staticTargetClass, Class dynamicTargetClass) {
+        super(staticTargetClass, dynamicTargetClass);
+    }
+
+    public String check (Class callerClass) {
+        /*
+         * If objectref is null, the invokespecial instruction throws a NullPointerException.
+         */
+        if (dynamicTargetClass == null) {
+            return "java.lang.NullPointerException";
+        }
+
+        /*
+         * TODO: find a citiation from spec for this case
+         */
+        Method resolvedMethod;
+        try {
+            // May throw VerifyError
+            resolvedMethod = getMethodInHierarchy(staticTargetClass);
+        } catch (Throwable e) {
+            return e.getClass().getName();
+        }
+
+        if (resolvedMethod == null) {
+            return "java.lang.NoSuchMethodError";
+        }
+
+       /*
+        * If:
+        *   - the resolved method is protected (4.7)
+        *   - it is a member of a superclass of the current class
+        *   - the method is not declared in the same run-time package (5.3) as the current class
+        * then:
+        *   the class of objectref must be either the current class or a subclass of the
+        * current class.
+        */
+
+        if (Modifier.isProtected(resolvedMethod.getModifiers())) {
+            Method methodInSuperclass = getMethodInHierarchy(resolvedMethod.getDeclaringClass().getSuperclass());
+
+            if (methodInSuperclass != null) {
+                String resolvedMethodPkg = getClassPackageName(resolvedMethod.getDeclaringClass());
+                String methodInSuperclassPkg = getClassPackageName(methodInSuperclass.getDeclaringClass());
+
+                if (!resolvedMethodPkg.equals(methodInSuperclassPkg)) {
+                    //TODO: clarify this
+//                    if (callerClass == methodInSuperclass.getDeclaringClass()) {
+//                        return "java.lang.IllegalAccessError";
+//                    }
+                }
+            }
+        }
+
+       /*
+        * The resolved method is selected for invocation unless all of
+        * the following conditions are true:
+        *     * TODO: The ACC_SUPER flag (see Table 4.1, "Class access and property
+        *       modifiers") is set for the current class.
+        *     * The class of the resolved method is a superclass of the
+        *       current class - assumed by construction procedure
+        *
+        *     * The resolved method is not an instance initialization method (3.9).
+        */
+        if (!"<init>".equals(methodName)) {
+           /*
+            * Let C be the direct superclass of the current class:
+            *    * If C contains a declaration for an instance method with the same
+            *      name and descriptor as the resolved method, then this method will be
+            *      invoked. The lookup procedure terminates.
+            *    * Otherwise, if C has a superclass, this same lookup procedure is
+            *      performed recursively using the direct superclass of C. The method to
+            *      be invoked is the result of the recursive invocation of this lookup
+            *      procedure.
+            *    * Otherwise, an AbstractMethodError is raised.
+            *      TODO: so far, sometimes NSME is thrown
+            */
+            Class klass = dynamicTargetClass.getSuperclass();
+
+            while (klass != Object.class) {
+                Method method = getDeclaredMethod(klass);
+
+                if (method != null) {
+                    /*
+                     * If the resolved method is a class (static) method, the
+                     * invokespecial instruction throws an IncompatibleClassChangeError.
+                     */
+                    if (Modifier.isStatic(method.getModifiers())) {
+                        return "java.lang.IncompatibleClassChangeError";
+                    }
+
+                    // Check access rights
+                    if ( checkAccess(method, callerClass)
+//                         && !(
+//                                 Modifier.isProtected(method.getModifiers())
+//                                 && (
+//                                     staticTargetClass.isAssignableFrom(callerClass)
+//                                     || getClassPackageName(staticTargetClass).equals(getClassPackageName(callerClass))
+//                                    )
+//
+//                            )
+                        )
+                    {
+                        return String.format("%s.%s"
+                                , method.getDeclaringClass().getSimpleName()
+                                , methodName
+                                );
+                    } else {
+                        // IAE is thrown when located method can't be accessed from the call site
+                        return "java.lang.IllegalAccessError";
+                    }
+                }
+
+                klass = klass.getSuperclass();
+            }
+
+            return "java.lang.AbstractMethodError";
+        } else {
+            // The resolved method is an instance initialization method (3.9).
+        }
+
+        // TODO: change
+        return "---";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokespecial/ClassGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokespecial;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import shared.GenericClassGenerator;
+
+/*******************************************************************/
+class ClassGenerator extends GenericClassGenerator<ClassGenerator> {
+    public ClassGenerator(String fullClassName, String parentClassName, int flags) {
+        super(fullClassName, parentClassName, flags);
+    }
+
+    // Add target method call site into current class
+    public ClassGenerator addCaller(String targetClass) {
+        return super.addCaller(targetClass, Opcodes.INVOKESPECIAL);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokespecial/Generator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * INVOKESPECIAL EXPECTED RESULTS
+ *
+ * From JVMS 3rd edition: invokespecial instruction:
+ *
+ * Invoke instance method; special handling for superclass, private, and instance
+ * initialization method invocations
+ *
+ * The named method is resolved (5.4.3.3). Finally, if the resolved method is
+ * protected (4.7), and it is a member of a superclass of the current class, and
+ * the method is not declared in the same run-time package (5.3) as the current
+ * class, then the class of objectref must be either the current class or a
+ * subclass of the current class.
+ *
+ * Next, the resolved method is selected for invocation unless all of the
+ * following conditions are true:
+ *     * The ACC_SUPER flag (see Table 4.1, "Class access and property modifiers") is set for the current class.
+ *     * The class of the resolved method is a superclass of the current class.
+ *     * The resolved method is not an instance initialization method (3.9).
+ *
+ * If the above conditions are true, the actual method to be invoked is selected
+ * by the following lookup procedure. Let C be the direct superclass of the
+ * current class:
+ *     * If C contains a declaration for an instance method with the same name and
+ *       descriptor as the resolved method, then this method will be invoked.
+ *       The lookup procedure terminates.
+ *
+ *     * Otherwise, if C has a superclass, this same lookup procedure is performed
+ *       recursively using the direct superclass of C. The method to be invoked is
+ *       the result of the recursive invocation of this lookup procedure.
+ *
+ *     * Otherwise, an AbstractMethodError? is raised.
+ *
+ * During resolution of the symbolic reference to the method, any of the
+ * exceptions pertaining to method resolution documented in Section 5.4.3.3 can be
+ * thrown.
+ *
+ * Otherwise, if the resolved method is an instance initialization method, and the
+ * class in which it is declared is not the class symbolically referenced by the
+ * instruction, a NoSuchMethodError? is thrown.
+ *
+ * Otherwise, if the resolved method is a class (static) method, the invokespecial
+ * instruction throws an IncompatibleClassChangeError?.
+ *
+ * Otherwise, if no method matching the resolved name and descriptor is selected,
+ * invokespecial throws an AbstractMethodError?.
+ *
+ * Otherwise, if the selected method is abstract, invokespecial throws an
+ * AbstractMethodError?.
+ *
+ * RUNTIME EXCEPTIONS
+ *
+ * Otherwise, if objectref is null, the invokespecial instruction throws a NullPointerException?.
+ *
+ * Otherwise, if the selected method is native and the code that implements the
+ * method cannot be bound, invokespecial throws an UnsatisfiedLinkError?.
+ *
+ * NOTES
+ *
+ * The difference between the invokespecial and the invokevirtual instructions is
+ * that invokevirtual invokes a method based on the class of the object. The
+ * invokespecial instruction is used to invoke instance initialization methods
+ * (3.9) as well as private methods and methods of a superclass of the current
+ * class.
+ *
+ * ACC_SUPER:
+ *
+ * The setting of the ACC_SUPER flag indicates which of two alternative semantics
+ * for its invokespecial instruction the Java virtual machine is to express; the
+ * ACC_SUPER flag exists for backward compatibility for code compiled by Sun's
+ * older compilers for the Java programming language. All new implementations of
+ * the Java virtual machine should implement the semantics for invokespecial
+ * documented in this specification. All new compilers to the instruction set of
+ * the Java virtual machine should set the ACC_SUPER flag. Sun's older compilers
+ * generated ClassFile? flags with ACC_SUPER unset. Sun's older Java virtual
+ * machine implementations ignore the flag if it is set.
+ *
+ * ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the
+ * invokespecial instruction.
+ *
+ * My Translation:
+ *     1. compile-time resolved class B
+ *     2. A,B,C direct superclass relationships
+ *     3. If B.m is protected
+ *          - if the caller is in B
+ *                then runtime resolved class must be in B or C
+ *          - if the caller is in C
+ *                then runtime resolved class must be in C
+ *     TODO: otherwise what is thrown? <noWikiWord>AbstractMethodError?
+ *     4. If B.m is an instance initialization method,
+ *          invoke B.m
+ *     5. If backward compatible caller does not set ACC_SUPER,
+ *          invoke B.m
+ *     6. If B is not a superclass of the caller, e.g. A is caller, or unrelated X
+ *        is the caller, invoke B.m
+ *     7. Otherwise:
+ *        If superclass of caller contains name/sig match, use it
+ *        Else, recursively through that superclass
+ *     8. If none found, throw AbstractMethodError
+ *
+ * Note: there is NO mention of overriding or accessibility in determining
+ * resolved method, except for if the compile-time type is protected.
+ *
+ * Case 1: B.m is protected
+ *         Caller in A: if runtime resolved class in A.m, AbstractMethodError
+ *         Caller in B: if runtime resolved class in A.m, AbstractMethodError
+ * Case 2: B.m is an instance initialization method
+ *         Always invoke B.m
+ * Case 3: older javac, caller does not set ACC_SUPER
+ *         Always invoke B.m
+ * Case 4: A or X (not in hierarchy) calls invokespecial on B.m, invoke B.m
+ * Case 5: Caller in B:
+ *           if A.m exists, call it, else <noWikiWord>AbstractMethodError
+ *         Caller in C:
+ *           if B.m exists, call it
+ *           if B.m does not exist, and A.m exists, call it
+ */
+
+//   TODO: classes without ACC_SUPER attribute
+//   TODO: B.m is an instance initialization method
+
+/*
+ *   invokespecial <method-spec>
+ *
+ * invokespecial is used in certain special cases to invoke a method
+ * Specifically, invokespecial is used to invoke:
+ *      - the instance initialization method, <init>
+ *      - a private method of this
+ *      - a method in a superclass of this
+ *
+ * The main use of invokespecial is to invoke an object's instance
+ * initialization method, <init>, during the construction phase for a new object.
+ * For example, when you write in Java:
+ *
+ *      new StringBuffer()
+ *
+ * code like the following is generated:
+ *      new java/lang/StringBuffer         ; create a new StringBuffer
+ *      dup                                ; make an extra reference to the new instance
+ *                                         ; now call an instance initialization method
+ *      invokespecial java/lang/StringBuffer/<init>()V
+ *                                         ; stack now contains an initialized StringBuffer.
+ *
+ * invokespecial is also used by the Java language by the 'super' keyword to
+ * access a superclass's version of a method. For example, in the class:
+ *
+ *     class Example {
+ *         // override equals
+ *         public boolean equals(Object x) {
+ *              // call Object's version of equals
+ *              return super.equals(x);
+ *         }
+ *     }
+ *
+ * the 'super.equals(x)' expression is compiled to:
+ *
+ *     aload_0  ; push 'this' onto the stack
+ *     aload_1  ; push the first argument (i.e. x) onto the stack
+ *              ; now invoke Object's equals() method.
+ *     invokespecial java/lang/Object/equals(Ljava/lang/Object;)Z
+ *
+ * Finally, invokespecial is used to invoke a private method. Remember that
+ * private methods are only visible to other methods belonging the same class as
+ * the private method.
+ *
+ * Before performing the method invocation, the class and the method identified
+ * by <method-spec> are resolved. See Chapter 9 for a description of how methods
+ * are resolved.
+ *
+ * invokespecial first looks at the descriptor given in <method-spec>, and
+ * determines how many argument words the method takes (this may be zero). It
+ * pops these arguments off the operand stack. Next it pops objectref (a
+ * reference to an object) off the operand stack. objectref must be an instance
+ * of the class named in <method-spec>, or one of its subclasses. The interpreter
+ * searches the list of methods defined by the class named in <method-spec>,
+ * looking for a method called methodname whose descriptor is descriptor. This
+ * search is not based on the runtime type of objectref, but on the compile time
+ * type given in <method-spec>.
+ *
+ * Once a method has been located, invokespecial calls the method. First, if
+ * the method is marked as synchronized, the monitor associated with objectref is
+ * entered. Next, a new stack frame structure is established on the call stack.
+ * Then the arguments for the method (which were popped off the current method's
+ * operand stack) are placed in local variables of the new stack frame structure.
+ * arg1 is stored in local variable 1, arg2 is stored in local variable 2 and so
+ * on. objectref is stored in local variable 0 (the local variable used for the
+ * special Java variable this). Finally, execution continues at the first
+ *instruction in the bytecode of the new method.
+ *
+ * Methods marked as native are handled slightly differently. For native
+ * methods, the runtime system locates the platform-specific code for the method,
+ * loading it and linking it into the JVM if necessary. Then the native method
+ * code is executed with the arguments popped from the operand stack. The exact
+ * mechanism used to invoke native methods is implementation-specific.
+ *
+ * When the method called by invokespecial returns, any single (or double) word
+ * return result is placed on the operand stack of the current method. If the
+ * invoked method was marked as synchronized, the monitor associated with
+ * objectref is exited. Execution continues at the instruction that follows
+ * invokespecial in the bytecode.
+ *
+ * Notes
+ *
+ * 1. In Java Virtual Machine implementations prior to version JDK 1.02, this
+ * instruction was called invokenonvirtual, and was less restrictive than
+ * invokespecial - it wasn't limited to invoking only superclass, private or
+ * <init> methods. The class access flag ACC_SUPER (see Chapter 4) is used to
+ * indicate which semantics are used by a class. In older class files, the
+ * ACC_SUPER flag is unset. In all new classes, the ACC_SUPER flag should be set,
+ * indicating that the restrictions enforced by invokespecial are obeyed. (In
+ * practice, all the common uses of invokenonvirtual continue to be supported
+ * by invokespecial, so this change should have little impact on JVM users).
+ *
+ */
+
+package invokespecial;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import shared.AbstractGenerator;
+import shared.AccessType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Generator extends AbstractGenerator {
+    public static void main (String[] args) throws Exception {
+        new Generator(args).run();
+    }
+    public Generator(String[] args) {
+        super(args);
+    }
+
+    protected Checker getChecker(Class paramClass, Class targetClass) {
+        return new Checker(paramClass, targetClass);
+    }
+
+    public void run() throws Exception {
+        // Specify package names
+        String pkg1 = "a.";
+        String pkg2 = "b.";
+        String[] packages = new String[] { "", pkg1, pkg2 };
+
+        boolean isPassed = true;
+
+        // HIERARCHIES
+        // The following triples will be used during further
+        // hierarchy construction and will specify packages for A, B and C
+        String[][] packageSets = new String[][] {
+              {   "",   "",   "" }
+            , {   "", pkg1, pkg1 }
+            , {   "", pkg1, pkg2 }
+            , { pkg1,   "", pkg1 }
+            , { pkg1,   "", pkg2 }
+            , { pkg1, pkg1,   "" }
+            , { pkg1, pkg2,   "" }
+            , { pkg1, pkg1, pkg1 }
+            , { pkg1, pkg1, pkg2 }
+            , { pkg1, pkg2, pkg1 }
+            , { pkg1, pkg2, pkg2 }
+        };
+
+        String [] header = new String[] {
+            String.format("%30s %35s", "Method access modifiers", "Call site location")
+                , String.format("%4s  %-10s %-10s %-10s   %7s %7s %7s %7s %7s %7s %7s"
+                        , "  # "
+                        , "A.m()"
+                        , "B.m()"
+                        , "C.m()"
+                        , "  A  "
+                        , "pkgA"
+                        , "  B  "
+                        , " pkgB"
+                        , "  C  "
+                        , "pkgC "
+                        , "  X  "
+                        )
+                , "-----------------------------------------------------------------------------------------------------------"
+        };
+
+        // Print header
+        for (String str : header) {
+            System.out.println(str);
+        }
+
+        // Iterate over all interesting package combinations
+        for (String[] pkgSet : packageSets) {
+            String packageA = pkgSet[0];
+            String packageB = pkgSet[1];
+            String packageC = pkgSet[2];
+
+            String classNameA = packageA + "A";
+            String classNameB = packageB + "B";
+            String classNameC = packageC + "C";
+
+            // For all possible access modifier combinations
+            for (AccessType accessFlagA : AccessType.values()) {
+                for (AccessType accessFlagB : AccessType.values()) {
+                    for (AccessType accessFlagC : AccessType.values()) {
+                        Map<String, byte[]> classes = new HashMap<String, byte[]>();
+
+                        String calleeClassName = classNameB;
+                        int classFlags = ACC_PUBLIC;
+
+                        // The following hierarhcy is created:
+                        //     c.C extends b.B extends a.A extends Object - base hierarchy
+                        //     X extends Object - external caller
+                        //     c.Caller, b.Caller, a.Caller extends Object - package callers
+
+                        // Generate result storage
+                        classes.put(
+                                "Result"
+                                , new ClassGenerator(
+                                    "Result"
+                                    , "java.lang.Object"
+                                    , ACC_PUBLIC
+                                    )
+                                .addField(
+                                    ACC_PUBLIC | ACC_STATIC
+                                    , "value"
+                                    , "java.lang.String"
+                                    )
+                                .getClassFile()
+                                );
+
+                        // Generate class A
+                        classes.put(
+                                classNameA
+                                , new ClassGenerator(
+                                    classNameA
+                                    , "java.lang.Object"
+                                    , classFlags
+                                    )
+                                .addTargetConstructor(accessFlagA)
+                                .addTargetMethod(accessFlagA)
+                                .addCaller(calleeClassName)
+                                .getClassFile()
+                                );
+
+                        // Generate class B
+                        classes.put(
+                                classNameB
+                                , new ClassGenerator(
+                                    classNameB
+                                    , classNameA
+                                    , classFlags
+                                    )
+                                .addTargetConstructor(accessFlagB)
+                                .addTargetMethod(accessFlagB)
+                                .addCaller(calleeClassName)
+                                .getClassFile()
+                                );
+
+                        // Generate class C
+                        classes.put(
+                                classNameC
+                                , new ClassGenerator(
+                                    classNameC
+                                    , classNameB
+                                    , classFlags
+                                    )
+                                .addTargetConstructor(accessFlagC)
+                                .addTargetMethod(accessFlagC)
+                                .addCaller(calleeClassName)
+                                .getClassFile()
+                                );
+
+                        // Generate class X
+                        String classNameX = "x.X";
+                        classes.put(
+                                classNameX
+                                , new ClassGenerator(
+                                    classNameX
+                                    , "java.lang.Object"
+                                    , classFlags
+                                    )
+                                .addTargetMethod(accessFlagC)
+                                .addCaller(calleeClassName)
+                                .getClassFile()
+                                );
+
+                        // Generate package callers
+                        for (String pkg : packages) {
+                            classes.put(
+                                    pkg+"Caller"
+                                    , new ClassGenerator(
+                                        pkg+"Caller"
+                                        , "java.lang.Object"
+                                        , classFlags
+                                        )
+                                    .addCaller(calleeClassName)
+                                    .getClassFile()
+                                    );
+                        }
+
+                        String[] callSites = new String[] {
+                                classNameA
+                                , packageA+"Caller"
+                                , classNameB
+                                , packageB+"Caller"
+                                , classNameC
+                                , packageC+"Caller"
+                                , classNameX
+                        };
+
+                        String caseDescription = String.format(
+                                    "%-10s %-10s %-10s| "
+                                    , classNameA + " " + accessFlagA
+                                    , classNameB + " " + accessFlagB
+                                    , classNameC + " " + accessFlagC
+                                    );
+
+                        boolean result = exec(classes, caseDescription, calleeClassName, classNameC, callSites);
+                        isPassed = isPassed && result;
+                    }
+                }
+            }
+        }
+
+        // Print footer
+        for (int i = header.length-1; i >= 0; i--) {
+            System.out.println(header[i]);
+        }
+
+        if (executeTests) {
+            System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokespecialTests.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8224137
+ * @summary Run invokespecial invocation tests
+ * @library /test/lib
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @compile shared/AbstractGenerator.java shared/AccessCheck.java shared/AccessType.java
+ *          shared/Caller.java shared/ExecutorGenerator.java shared/Utils.java
+ *          shared/ByteArrayClassLoader.java shared/Checker.java shared/GenericClassGenerator.java
+ * @compile invokespecial/Checker.java invokespecial/ClassGenerator.java invokespecial/Generator.java
+ *
+ * @run main/othervm/timeout=1800 invokespecialTests
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class invokespecialTests {
+
+    public static void runTest(String classFileVersion, String option) throws Exception {
+        System.out.println("\ninvokespecial invocation tests, option: " + option +
+                           ", class file version: " + classFileVersion);
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false, "-Xmx128M", option,
+            "invokespecial.Generator", "--classfile_version=" + classFileVersion);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        try {
+            output.shouldContain("EXECUTION STATUS: PASSED");
+            output.shouldHaveExitValue(0);
+        } catch (Throwable e) {
+            System.out.println(
+                "\nNote that an entry such as 'B.m/C.m' in the failure chart means that" +
+                " the test case failed because method B.m was invoked but the test " +
+                "expected method C.m to be invoked. Similarly, a result such as 'AME/C.m'" +
+                " means that an AbstractMethodError exception was thrown but the test" +
+                " case expected method C.m to be invoked.");
+            System.out.println(
+                "\nAlso note that passing --dump to invokespecial.Generator will" +
+                " dump the generated classes (for debugging purposes).\n");
+            System.exit(1);
+        }
+    }
+
+    public static void main(String args[]) throws Throwable {
+        // Get current major class file version and test with it.
+        byte klassbuf[] = InMemoryJavaCompiler.compile("blah", "public class blah { }");
+        int major_version = klassbuf[6] << 8 | klassbuf[7];
+        runTest(String.valueOf(major_version), "-Xint");
+        runTest(String.valueOf(major_version), "-Xcomp");
+
+        // Test old class file version.
+        runTest("51", "-Xint"); // JDK-7
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokevirtual/Checker.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokevirtual;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+
+public class Checker extends shared.Checker {
+    public Checker(Class staticTargetClass, Class dynamicTargetClass) {
+        super(staticTargetClass, dynamicTargetClass);
+    }
+
+    public String check (Class callerClass) {
+        Method m;
+        try {
+            // May cause java.lang.VerifyError
+            m = getOverriddenMethod();
+        } catch (Throwable e) {
+            return e.getClass().getName();
+        }
+
+        // Check method accessibility (it's a static property, according to JLS #6.6: Access Control)
+        if (m != null) {
+            Method staticTargetMethod = getDeclaredMethod(staticTargetClass);
+
+            if (checkAccess(staticTargetMethod, callerClass)) {
+                // Can't invoke abstract method
+                if ( Modifier.isAbstract(m.getModifiers())) {
+                    return "java.lang.AbstractMethodError";
+                }
+
+                return String.format("%s.%s"
+                        , m.getDeclaringClass().getSimpleName()
+                        , methodName
+                        );
+            } else {
+                // if method isn't accessible, IllegalAccessError is thrown
+                return "java.lang.IllegalAccessError";
+            }
+        } else {
+            // if method == null, NoSuchMethodError is thrown
+            return "java.lang.NoSuchMethodError";
+        }
+    }
+
+    public Method getOverriddenMethod() {
+        return getOverriddenMethod(staticTargetClass, dynamicTargetClass);
+    }
+
+    public Method getOverriddenMethod(Class staticTarget, Class dynamicTarget) {
+        // Assertion #1. C is a subclass of A
+        if (!staticTarget.isAssignableFrom(dynamicTarget)) {
+            return null;
+        }
+
+        Method staticTargetMethod = getDeclaredMethod(staticTarget);
+        Method dynamicTargetMethod = getDeclaredMethod(dynamicTarget);
+
+        if (staticTarget.equals(dynamicTarget)) {
+            return staticTargetMethod;
+        }
+
+        // TODO: ? need to find out the right behavior
+        if (staticTargetMethod == null) {
+            return null;
+        }
+
+        // Dynamic target doesn't have desired method, so check it's superclass
+        if (dynamicTargetMethod == null) {
+            return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass());
+        } else {
+            // Private method can't override anything
+            if (Modifier.isPrivate(dynamicTargetMethod.getModifiers())) {
+                return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass());
+            }
+        }
+
+        // TODO: abstract methods
+
+        //Assertion #3.a: A.m2 is PUB || PROT || (PP && PKG(A) == PKG(C))
+        int staticTargetModifiers = staticTargetMethod.getModifiers();
+        {
+            boolean isPublic = Modifier.isPublic(staticTargetModifiers);
+            boolean isProtected = Modifier.isProtected(staticTargetModifiers);
+            boolean isPrivate = Modifier.isPrivate(staticTargetModifiers) ;
+            String staticTargetPkg = getClassPackageName(staticTarget);
+            String dynamicTargetPkg = getClassPackageName(dynamicTarget);
+
+            if ( isPublic || isProtected
+                 || ( !isPublic && !isProtected && !isPrivate
+                      && staticTargetPkg.equals(dynamicTargetPkg)
+                    ))
+            {
+                return dynamicTargetMethod;
+            }
+        }
+        // OR
+        //Assertion #3.b: exists m3: C.m1 != B.m3, A.m2 != B.m3, B.m3 overrides A.m2, C.m1 overrides B.m3
+        Class ancestor = dynamicTarget.getSuperclass();
+        while (ancestor != staticTarget) {
+            Method OverriddenM2 = getOverriddenMethod(staticTarget, ancestor);
+            Method m3 = getDeclaredMethod(ancestor);
+            Method m1 = getOverriddenMethod(ancestor, dynamicTarget);
+
+            if (m1 != null && m3 != null) {
+                if (m1.equals(dynamicTargetMethod) && m3.equals(OverriddenM2)) {
+                    return dynamicTargetMethod;
+                }
+            } else {
+                if (m1 == null && dynamicTargetMethod == null
+                    && m3 == null && OverriddenM2 == null)
+                {
+                    return null;
+                }
+            }
+
+            ancestor = ancestor.getSuperclass();
+        }
+
+        return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokevirtual/ClassGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokevirtual;
+
+import jdk.internal.org.objectweb.asm.Opcodes;
+import shared.GenericClassGenerator;
+
+/*******************************************************************/
+class ClassGenerator extends GenericClassGenerator<ClassGenerator> {
+    public ClassGenerator(String fullClassName) {
+        super(fullClassName);
+    }
+
+    public ClassGenerator(String fullClassName, String parentClassName) {
+        super(fullClassName, parentClassName);
+    }
+
+    public ClassGenerator(String fullClassName, String parentClassName, int flags) {
+        super(fullClassName, parentClassName, flags);
+    }
+
+    // Add target method call site into current class
+    public ClassGenerator addCaller(String targetClass) {
+        return super.addCaller(targetClass, Opcodes.INVOKEVIRTUAL);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokevirtual/Generator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package invokevirtual;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
+import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import shared.AbstractGenerator;
+import shared.AccessType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Generator extends AbstractGenerator {
+    public Generator(String[] args) {
+        super(args);
+    }
+
+    public static void main (String[] args) throws Exception {
+        new Generator(args).run();
+    }
+
+    protected Checker getChecker(Class paramClass, Class targetClass) {
+        return new Checker(paramClass, targetClass);
+    }
+
+    private void run() throws Exception {
+        // Specify package names
+        String pkg1 = "a.";
+        String pkg2 = "b.";
+        String pkg3 = "c.";
+        String[] packages = new String[] { "", pkg1, pkg2, pkg3 };
+
+        boolean isPassed = true;
+
+        // Hierarchy
+        // The following triples will be used during further
+        // hierarchy construction and will specify packages for A, B and C
+        String[][] packageSets = new String[][] {
+                {   "",   "",   "" }
+                , {   "", pkg1, pkg1 }
+                , {   "", pkg1, pkg2 }
+                , { pkg1, pkg1, pkg1 }
+                , { pkg1, pkg1, pkg2 }
+                , { pkg1, pkg2, pkg1 }
+                , { pkg1, pkg2, pkg2 }
+        };
+
+        String [] header = new String[] {
+                String.format("%30s %45s %20s", "Method access modifiers", "Call site location", "Status")
+                , String.format("%4s  %-12s %-12s %-12s   %7s %7s %7s %7s %7s %7s"
+                        , "  # "
+                        , "A.m()"
+                        , "B.m()"
+                        , "C.m()"
+                        , "  A  "
+                        , "pkgA "
+                        , "  B  "
+                        , " pkgB"
+                        , "  C  "
+                        , "pkgC "
+                        )
+                , "-------------------------------------------------------------------------------------------------"
+        };
+
+        for (String str : header) {
+            System.out.println(str);
+        }
+
+        for (String[] pkgSet : packageSets) {
+            String packageA = pkgSet[0];
+            String packageB = pkgSet[1];
+            String packageC = pkgSet[2];
+
+            String classNameA = packageA + "A";
+            String classNameB = packageB + "B";
+            String classNameC = packageC + "C";
+
+            String staticCallerParam = classNameA;
+
+            // For all possible access modifier combinations
+            for (AccessType accessA : AccessType.values()) {
+                for (AccessType accessB : AccessType.values()) {
+                    for (AccessType accessC : AccessType.values()) {
+
+                        if (accessA == AccessType.UNDEF) {
+                            continue;
+                        }
+
+                        for (int I = 0; I < 4; I++) {
+                            boolean isAbstractA = ((I & 1) != 0);
+                            boolean isAbstractB = ((I & 2) != 0);
+
+                            Map<String, byte[]> classes = new HashMap<String, byte[]>();
+
+                            // Generate class A
+                            classes.put(
+                                    classNameA
+                                    , new ClassGenerator( classNameA
+                                                        , "java.lang.Object"
+                                                        , ACC_PUBLIC | (isAbstractA ? ACC_ABSTRACT : 0))
+                                        .addTargetMethod( accessA
+                                                        , (isAbstractA ? ACC_ABSTRACT : 0))
+                                        .addCaller(staticCallerParam)
+                                        .getClassFile()
+                            );
+
+                            // Generate class B
+                            classes.put(
+                                    classNameB
+                                    , new ClassGenerator( classNameB
+                                                        , classNameA
+                                                        , ACC_PUBLIC | (isAbstractB ? ACC_ABSTRACT : 0))
+                                    .addTargetMethod( accessB
+                                                    , (isAbstractB ? ACC_ABSTRACT : 0))
+                                    .addCaller(staticCallerParam)
+                                    .getClassFile()
+                            );
+
+                            // Generate class C
+                            classes.put(
+                                    classNameC
+                                    , new ClassGenerator(classNameC, classNameB)
+                                        .addTargetMethod(accessC)
+                                        .addCaller(staticCallerParam)
+                                        .getClassFile()
+                            );
+
+                            // Generate package callers
+                            for (String pkg : packages) {
+                                classes.put(
+                                        pkg+"Caller"
+                                        , new ClassGenerator(pkg+"Caller")
+                                        .addCaller(staticCallerParam)
+                                        .getClassFile()
+                                );
+                            }
+
+                            String[] callSites = new String[] {
+                                    classNameA
+                                    , packageA+"Caller"
+                                    , classNameB
+                                    , packageB+"Caller"
+                                    , classNameC
+                                    , packageC+"Caller"
+                            };
+
+
+                            String caseDescription =
+                                    String.format("%-12s %-12s %-12s| "
+                                        , (isAbstractA ? "! " : "  ") + classNameA + " " + accessA
+                                        , (isAbstractB ? "! " : "  ") + classNameB + " " + accessB
+                                        , classNameC + " " + accessC
+                                    );
+
+                            boolean result = exec(classes, caseDescription, staticCallerParam, classNameC, callSites);
+                            isPassed = isPassed && result;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Print footer
+        for (int i = header.length-1; i >= 0; i--) {
+            System.out.println(header[i]);
+        }
+
+        if (executeTests) {
+            System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/invokevirtualTests.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8224137
+ * @summary Run invokevirtual invocation tests
+ * @library /test/lib
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.misc
+ * @compile shared/AbstractGenerator.java shared/AccessCheck.java shared/AccessType.java
+ *          shared/Caller.java shared/ExecutorGenerator.java shared/Utils.java
+ *          shared/ByteArrayClassLoader.java shared/Checker.java shared/GenericClassGenerator.java
+ * @compile invokevirtual/Checker.java invokevirtual/ClassGenerator.java invokevirtual/Generator.java
+ *
+ * @run main/othervm/timeout=1800 invokevirtualTests
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+
+public class invokevirtualTests {
+
+    public static void runTest(String classFileVersion, String option) throws Exception {
+        System.out.println("\ninvokevirtual invocation tests, option: " + option +
+                           ", class file version: " + classFileVersion);
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false, "-Xmx128M", option,
+            "invokevirtual.Generator", "--classfile_version=" + classFileVersion);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        try {
+            output.shouldContain("EXECUTION STATUS: PASSED");
+            output.shouldHaveExitValue(0);
+        } catch (Throwable e) {
+            System.out.println(
+                "\nNote that an entry such as 'B.m/C.m' in the failure chart means that" +
+                " the test case failed because method B.m was invoked but the test " +
+                "expected method C.m to be invoked. Similarly, a result such as 'AME/C.m'" +
+                " means that an AbstractMethodError exception was thrown but the test" +
+                " case expected method C.m to be invoked.");
+            System.out.println(
+                "\nAlso note that passing --dump to invokevirtual.Generator will" +
+                " dump the generated classes (for debugging purposes).\n");
+            System.exit(1);
+        }
+    }
+
+    public static void main(String args[]) throws Throwable {
+        // Get current major class file version and test with it.
+        byte klassbuf[] = InMemoryJavaCompiler.compile("blah", "public class blah { }");
+        int major_version = klassbuf[6] << 8 | klassbuf[7];
+        runTest(String.valueOf(major_version), "-Xint");
+// Uncomment the below test once JDK-8226588 is fixed
+//      runTest(String.valueOf(major_version), "-Xcomp");
+
+        // Test old class file version.
+        runTest("51", "-Xint"); // JDK-7
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/AbstractGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ *
+ */
+public abstract class AbstractGenerator {
+    protected final boolean dumpClasses;
+    protected final boolean executeTests;
+    private static int testNum = 0;
+
+    protected AbstractGenerator(String[] args) {
+        List<String> params = new ArrayList<String>(Arrays.asList(args));
+
+        if (params.contains("--help")) {
+            Utils.printHelp();
+            System.exit(0);
+        }
+
+        dumpClasses = params.contains("--dump");
+        executeTests = !params.contains("--noexecute");
+
+        params.remove("--dump");
+        params.remove("--noexecute");
+
+        Utils.init(params);
+    }
+
+    /*******************************************************************/
+    public static void writeToFile(File dir, Map<String, byte[]> classes) {
+        for (String name : classes.keySet()) {
+            try {
+                writeToFile(dir, name, classes.get(name));
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /*******************************************************************/
+    public static void writeToFile(File dir, String fullName, byte[] classBytecode) {
+        if (!dir.isDirectory()) {
+            throw new RuntimeException("Invalid parameter: dir doesn't point to an existing directory");
+        }
+
+        File classFile =
+            new File(
+                    dir.getPath() + File.separator
+                    + fullName.replaceAll("\\.", File.separator)
+                    + ".class"
+                    );
+
+        classFile.getParentFile().mkdirs();
+
+        try {
+            FileOutputStream fos = new FileOutputStream(classFile);
+            try {
+                fos.write(classBytecode);
+            } finally {
+                fos.close();
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected boolean exec(Map<String, byte[]> classes, String description, String calleeClassName, String classNameC, String[] callSites) throws ClassNotFoundException {
+        boolean isPassed = true;
+
+        testNum++;
+
+        String caseDescription = String.format("%4d| %s", testNum, description);
+
+        // Create test executor for a single case
+        classes.put(
+                ExecutorGenerator.className
+                , new ExecutorGenerator(
+                        caseDescription
+                        , calleeClassName
+                        , classNameC
+                    ).generateExecutor(callSites)
+        );
+
+        // Dump generated set to disk, if needed
+        if (dumpClasses) {
+            File dir = new File("classes" + File.separator + String.format("%04d", testNum));
+            dir.mkdirs();
+            writeToFile(dir, classes);
+        }
+
+        ByteArrayClassLoader loader = new ByteArrayClassLoader(classes);
+
+        Class paramClass;
+        Class targetClass;
+        Checker checker;
+
+        try {
+            paramClass = loader.loadClass(calleeClassName);
+            targetClass = loader.loadClass(classNameC);
+
+            checker = getChecker(paramClass, targetClass);
+        } catch (Throwable e) {
+            String result = Checker.abbreviateResult(e.getClass().getName());
+
+            System.out.printf(caseDescription);
+
+            for (String site : callSites) {
+                System.out.printf(" %7s", result);
+            }
+
+            System.out.println("");
+
+            return true;
+        }
+
+        if (executeTests) {
+            // Check runtime behavior
+            Caller caller = new Caller(loader, checker, paramClass, targetClass);
+            boolean printedCaseDes = false;
+            for (String site : callSites) {
+                String callResult = caller.call(site);
+
+                if (!caller.isPassed()) {
+                    isPassed = false;
+                    if (!printedCaseDes) {
+                        System.out.printf(caseDescription);
+                        printedCaseDes = true;
+                    }
+                    System.out.printf(" %7s", callResult);
+                }
+            }
+            if (!caller.isPassed()) {
+                System.out.println(" |   FAILED");
+            }
+        } else {
+            for (String site : callSites) {
+                String result = checker.check(loader.loadClass(site));
+                System.out.printf(" %7s", Checker.abbreviateResult(result));
+            }
+        }
+
+        return isPassed;
+    }
+
+    protected abstract Checker getChecker(Class paramClass, Class targetClass);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/AccessCheck.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+/**
+ *
+ * @author vi158347
+ */
+public class AccessCheck {
+    public static boolean isAbstract(int access) {
+        return (access & ACC_ABSTRACT) != 0;
+    }
+
+    public static boolean isPublic(int access) {
+        return (access & ACC_PUBLIC) != 0;
+    }
+
+    public static boolean isProtected(int access) {
+        return (access & ACC_PROTECTED) != 0;
+    }
+
+    public static boolean isPackagePrivate(int access) {
+        return !isPublic(access) && !isProtected(access) && !isPrivate(access);
+    }
+
+    public static boolean isPrivate(int access) {
+        return (access & ACC_PRIVATE) != 0;
+    }
+
+    public static boolean isInterface(int access) {
+        return (access & ACC_INTERFACE) != 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/AccessType.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+public enum AccessType {
+      PUBLIC           ("PUB")   { public int value() { return ACC_PUBLIC; } }
+    , PROTECTED        ("PROT")  { public int value() { return ACC_PROTECTED; } }
+    , PACKAGE_PRIVATE  ("PP")    { public int value() { return 0; } }
+    , PRIVATE          ("PRIV")  { public int value() { return ACC_PRIVATE; } }
+    , UNDEF            ("UNDEF") { public int value() { return -1; } }
+    ;
+
+    private String name;
+
+    AccessType(String name) {
+        this.name = name;
+    }
+
+    public abstract int value();
+
+    public String toString() {
+        return name;
+    }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/ByteArrayClassLoader.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/*******************************************************************/
+// Class loader which has local class file storage in memory
+/*******************************************************************/
+
+public class ByteArrayClassLoader extends ClassLoader {
+    private Map<String, byte[]> classes;
+
+    public ByteArrayClassLoader() {
+        classes = new HashMap<String, byte[]>();
+    }
+
+    public ByteArrayClassLoader(Map<String, byte[]> classes) {
+        this.classes = classes;
+    }
+
+    public void appendClass(String name, byte[] classFile) {
+        classes.put(name, classFile);
+    }
+
+    public Class findClass (String name) throws ClassNotFoundException {
+        if (classes.containsKey(name)) {
+            byte[] classData = classes.get(name);
+            return defineClass(name, classData, 0, classData.length);
+        } else {
+            throw new ClassNotFoundException("Can't find requested class: " + name);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/Caller.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import java.lang.reflect.InvocationTargetException;
+
+/*******************************************************************/
+// Invoke different target method callers
+/*******************************************************************/
+
+public class Caller {
+    private ClassLoader loader;
+    private Class paramClass;
+    private Class targetClass;
+    private boolean passed = true;
+    private Checker checker;
+
+    public Caller(ClassLoader loader, Checker checker,
+                  Class paramClass, Class targetClass) {
+        this.loader = loader;
+        this.paramClass = paramClass;
+        this.targetClass = targetClass;
+        this.checker = checker;
+    }
+
+    public boolean isPassed() {
+        return passed;
+    }
+
+    public String call(String invoker) {
+        try {
+            Class clazz = loader.loadClass(invoker);
+
+            String expectedBehavior = checker.check(clazz);
+
+            String result = null;
+            Throwable exc = null;
+            try {
+                java.lang.reflect.Method m = clazz.getDeclaredMethod("call", paramClass);
+                result = (String) m.invoke(null, targetClass.newInstance());
+            } catch (InvocationTargetException e) {
+                exc = e.getCause();
+            } catch (Throwable e) {
+                exc = e;
+            }
+
+            if (result == null) {
+                if (exc != null) {
+                    result = exc.getClass().getName();
+                } else {
+                    result = "null";
+                }
+            }
+
+            if (!(result.equals(expectedBehavior) || "".equals(expectedBehavior)) ) {
+                passed = false;
+                result = String.format("%s/%s", result, expectedBehavior);
+            }
+
+            return Checker.abbreviateResult(result);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/Checker.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public abstract class Checker {
+    protected Class staticTargetClass;
+    protected Class dynamicTargetClass;
+    protected String methodName;
+
+    public abstract String check (Class callSite);
+
+    public Checker(Class staticTargetClass, Class dynamicTargetClass) {
+        if (!staticTargetClass.isAssignableFrom(dynamicTargetClass)) {
+            throw new RuntimeException("Dynamic target class should be a subclass of the static target class.");
+        }
+
+        // **********************************************
+        // NB!!! All classes are assumed to be PUBLIC !!!
+        // **********************************************
+        Class klass = dynamicTargetClass;
+        while (klass != Object.class) {
+            if (!Modifier.isPublic(klass.getModifiers())) {
+                throw new AssertionError("Class "+klass.getName()+" isn't public.");
+            }
+
+            klass = klass.getSuperclass();
+        }
+
+        this.methodName = Utils.TARGET_METHOD_NAME;
+        this.staticTargetClass = staticTargetClass;
+        this.dynamicTargetClass = dynamicTargetClass;
+    }
+
+    protected Method getMethodInHierarchy (Class klass) {
+        return getMethodInHierarchy(klass, methodName);
+    }
+
+    protected Method getMethodInHierarchy (Class klass, String name) {
+        while (klass != null) {
+            Method method = getDeclaredMethod (klass, name);
+
+            if ( method != null) {
+// TODO: why doesn't this check work in VM?
+//                int modifiers = method.getModifiers();
+//
+//                if (Modifier.isPrivate(modifiers)) {
+//                    if (klass == initialClass) {
+//                        return method;
+//                    }
+//                } else {
+//                    return method;
+//                }
+                return method;
+            }
+            klass = klass.getSuperclass();
+        }
+
+        return null;
+    }
+
+    protected Method getMethod (Class klass) {
+        return getMethod (klass, methodName);
+    }
+
+    protected Method getDeclaredMethod (Class klass) {
+        return getDeclaredMethod (klass, methodName);
+    }
+
+    static protected Method getMethod (Class klass, String name) {
+        return findMethod (klass.getMethods(), name);
+    }
+
+    static protected Method getDeclaredMethod (Class klass, String name) {
+        return findMethod (klass.getDeclaredMethods(), name);
+    }
+
+    static protected Method findMethod (Method[] methods, String name) {
+        for (Method method : methods) {
+            if (name.equals(method.getName())) {
+                return method;
+            }
+        }
+
+        return null;
+    }
+
+    static public String getClassPackageName(Class klass) {
+        String name = klass.getName();
+        return getClassPackageName(name);
+    }
+
+    static public String getClassPackageName(String name) {
+        int lastDotIndex = name.lastIndexOf('.');
+        if (lastDotIndex > -1) {
+            return name.substring(0, lastDotIndex);
+        } else {
+            return "";
+        }
+    }
+
+    public static String abbreviateResult(String result) {
+        // Abbreviate exception names
+        result = result.replaceAll("java.lang.NullPointerException", "NPE");
+        result = result.replaceAll("java.lang.IllegalAccessError", "IAE");
+        result = result.replaceAll("java.lang.IllegalAccessException", "IAExc");
+        result = result.replaceAll("java.lang.NoSuchMethodError", "NSME");
+        result = result.replaceAll("java.lang.AbstractMethodError", "AME");
+        result = result.replaceAll("java.lang.IncompatibleClassChangeError", "ICCE");
+        result = result.replaceAll("java.lang.VerifyError", "VE");
+        result = result.replaceAll("java.lang.ClassFormatError", "CFE");
+
+        return result;
+    }
+
+    // Check access possibility from particular call site
+    protected boolean checkAccess(Class klass, Class callerClass) {
+        int modifiers = klass.getModifiers();
+
+        return checkAccess(modifiers, klass, callerClass);
+    }
+
+    protected boolean checkAccess(Method m, Class callerClass) {
+        int modifiers = m.getModifiers();
+        Class declaringClass = m.getDeclaringClass();
+
+        return checkAccess(modifiers, declaringClass, callerClass);
+    }
+
+    protected boolean checkAccess(int modifiers, Class klass, Class callerClass) {
+        if ( Modifier.isPublic(modifiers) ) {
+            return true;
+        } else if ( Modifier.isProtected(modifiers) ) {
+            if (klass.isAssignableFrom(callerClass)) {
+                return true;
+            } else if (getClassPackageName(klass).equals(getClassPackageName(callerClass))) {
+                return true;
+            }
+        } else if ( Modifier.isPrivate(modifiers)) {
+            if (klass == callerClass) {
+                return true;
+            }
+        } else if (getClassPackageName(klass).equals(getClassPackageName(callerClass))) {
+            return true;
+        } else {
+            // if method isn't accessible, IllegalAccessException is thrown
+            return false;
+        }
+
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/ExecutorGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import static jdk.internal.org.objectweb.asm.ClassWriter.*;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+public class ExecutorGenerator {
+    public static final String className = Utils.getInternalName("Test");
+    private String caseDescription;
+    private String staticTargetName;
+    private String dynamicTargetName;
+
+    private String callerSignature;
+
+    public ExecutorGenerator(String caseDescription,
+                             String staticTargetName,
+                             String dynamicTargetName) {
+        this.caseDescription = caseDescription;
+        this.staticTargetName = Utils.getInternalName(staticTargetName);
+        this.dynamicTargetName = Utils.getInternalName(dynamicTargetName);
+        callerSignature = String.format("(L%s;)Ljava/lang/String;", this.staticTargetName);
+    }
+
+    public byte[] generateExecutor(String[] callSites) {
+        ClassWriter cw = new ClassWriter(COMPUTE_MAXS);
+
+        cw.visit(Utils.version, ACC_PUBLIC | (Utils.isACC_SUPER ? ACC_SUPER : 0), className, null, "java/lang/Object", null);
+
+        // Generate constructor
+        {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+            mv.visitInsn(RETURN);
+            mv.visitEnd();
+            mv.visitMaxs(0, 0);
+        }
+
+        // public static void main(String[] args) {
+        //      new Test().run();
+        // }
+        {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+            mv.visitCode();
+            mv.visitTypeInsn(NEW, className);
+            mv.visitInsn(DUP);
+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
+            mv.visitMethodInsn(INVOKEVIRTUAL, className, "run", "()V");
+            mv.visitInsn(RETURN);
+            mv.visitEnd();
+            mv.visitMaxs(0, 0);
+        }
+
+        //    private String indent(String result) {
+        //        while (result.length() < 8) {
+        //            result = " "+result;
+        //        }
+        //        return result;
+        //    }
+        {
+            MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "indent", "(Ljava/lang/String;)Ljava/lang/String;", null, null);
+            mv.visitCode();
+            Label l0 = new Label();
+            mv.visitLabel(l0);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I");
+            mv.visitIntInsn(BIPUSH, 8);
+            Label l1 = new Label();
+            mv.visitJumpInsn(IF_ICMPGE, l1);
+            mv.visitTypeInsn(NEW, "java/lang/StringBuffer");
+            mv.visitInsn(DUP);
+            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V");
+            mv.visitLdcInsn(" ");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitJumpInsn(GOTO, l0);
+            mv.visitLabel(l1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitInsn(ARETURN);
+            mv.visitEnd();
+            mv.visitMaxs(0, 0);
+        }
+
+        //private String abbr(String result) {
+        //      result = result.replaceAll("java.lang.NullPointerException", "NPE");
+        //      result = result.replaceAll("java.lang.IllegalAccessError", "IAE");
+        //      result = result.replaceAll("java.lang.IllegalAccessException", "IAExc");
+        //      result = result.replaceAll("java.lang.NoSuchMethodError", "NSME");
+        //      result = result.replaceAll("java.lang.AbstractMethodError", "AME");
+        //      result = result.replaceAll("java.lang.IncompatibleClassChangeError", "ICCE");
+        //
+        //      return result;
+        //}
+        {
+            MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "abbr", "(Ljava/lang/String;)Ljava/lang/String;", null, null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.NullPointerException");
+            mv.visitLdcInsn("NPE");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.IllegalAccessError");
+            mv.visitLdcInsn("IAE");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.IllegalAccessException");
+            mv.visitLdcInsn("IAExc");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.NoSuchMethodError");
+            mv.visitLdcInsn("NSME");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.AbstractMethodError");
+            mv.visitLdcInsn("AME");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitLdcInsn("java.lang.IncompatibleClassChangeError");
+            mv.visitLdcInsn("ICCE");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+            mv.visitVarInsn(ASTORE, 1);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitInsn(ARETURN);
+            mv.visitEnd();
+            mv.visitMaxs(0, 0);
+        }
+
+        // Generate execution method
+        //        public void run() {
+        //            System.out.print("2048| ! a.A PUB    ! b.B PP     a.C PROT    |");
+        //
+        //            C object = new C();
+        //
+        //            try {
+        //              System.out.print(indent(A.call(object)));
+        //            } catch (Throwable e) {
+        //              System.out.print(indent(abbr(e.getClass().getName())));
+        //            }
+        //
+        //            ...
+        //
+        //            System.out.println();
+        //        }
+        {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
+            mv.visitCode();
+
+            // Generate try/catch blocks
+            Label[][] tryCatchLabels = new Label[callSites.length][3];
+            for (int I = 0; I < tryCatchLabels.length; I++) {
+                Label[] labels = tryCatchLabels[I];
+                for (int K = 0; K < labels.length; K++) {
+                    labels[K] = new Label();
+                }
+
+                mv.visitTryCatchBlock(labels[0], labels[1], labels[2], "java/lang/Throwable");
+            }
+
+            // System.out.print("2048| ! a.A PUB    ! b.B PP     a.C PROT    |");
+            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+            mv.visitLdcInsn(caseDescription);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
+
+            // C object = new C();
+            mv.visitTypeInsn(NEW, dynamicTargetName);
+            mv.visitInsn(DUP);
+            mv.visitMethodInsn(INVOKESPECIAL, dynamicTargetName, "<init>", "()V");
+            mv.visitVarInsn(ASTORE, 1);
+
+//            for (String site: callSites) {
+            // System.out.print(indent(A.call(object)));
+//                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+//                mv.visitVarInsn(ALOAD, 0);
+//                mv.visitVarInsn(ALOAD, 1);
+//                mv.visitMethodInsn(INVOKESTATIC, AbstractGenerator.getInternalName(site), "call", callerSignature);
+//                mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;");
+//                mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
+//        }
+
+            Label returnLabel = new Label();
+            for (int I = 0; I < callSites.length; I++) {
+                String site = callSites[I];
+                Label[] l = tryCatchLabels[I];
+
+                Label nextBlock = (I+1 < callSites.length ? tryCatchLabels[I+1][0] : returnLabel);
+
+                mv.visitLabel(l[0]);
+                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitVarInsn(ALOAD, 1);
+                mv.visitMethodInsn(INVOKESTATIC, Utils.getInternalName(site), "call", callerSignature);
+                mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;");
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
+                mv.visitLabel(l[1]);
+                mv.visitJumpInsn(GOTO, nextBlock);
+                mv.visitLabel(l[2]);
+                mv.visitVarInsn(ASTORE, 2);
+                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitVarInsn(ALOAD, 2);
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
+                mv.visitMethodInsn(INVOKESPECIAL, className, "abbr", "(Ljava/lang/String;)Ljava/lang/String;");
+                mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;");
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V");
+            }
+            mv.visitLabel(returnLabel);
+
+            // System.out.println();
+            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "()V");
+            mv.visitInsn(RETURN);
+
+            mv.visitEnd();
+            mv.visitMaxs(0, 0);
+        }
+
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/GenericClassGenerator.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
+import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import static shared.AccessCheck.*;
+
+public class GenericClassGenerator<T extends GenericClassGenerator> {
+    private static final String targetMethodName = Utils.TARGET_METHOD_NAME;
+
+    private int flags = 0;
+    private ClassWriter writer;
+    private String fullClassName = null;
+    private String parentClassName = null;
+
+    /*******************************************************************/
+    public GenericClassGenerator(String fullClassName) {
+        this(fullClassName, "java/lang/Object");
+    }
+
+    /*******************************************************************/
+    public GenericClassGenerator(String fullClassName, String parentClassName ) {
+        this(fullClassName, parentClassName, ACC_PUBLIC);
+    }
+
+    /*******************************************************************/
+    public GenericClassGenerator(String fullClassName, String parentClassName, int flags) {
+        this(fullClassName, parentClassName, flags, new String[0]);
+    }
+
+    /*******************************************************************/
+    public GenericClassGenerator(String fullClassName, String parentClassName, int flags, String[] implementedInterfaces) {
+        writer = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);
+
+        this.fullClassName = fullClassName;
+        this.flags = flags;
+
+        // Construct simple class
+        if (parentClassName != null) {
+            this.parentClassName = getInternalName(parentClassName);
+        } else {
+            this.parentClassName = "java/lang/Object";
+        }
+
+        String parent = this.parentClassName;
+        String name = getInternalName(fullClassName);
+
+        if (Utils.isACC_SUPER) {
+            flags = flags | ACC_SUPER;
+        }
+
+        writer.visit(Utils.version, flags, name, null, parent, implementedInterfaces);
+
+        // Add constructor
+        if ( !isInterface(flags) ) {
+            MethodVisitor m =
+                    writer.visitMethod(
+                            ACC_PUBLIC
+                            , "<init>"
+                            , "()V"
+                            , null
+                            , null
+                    );
+
+            m.visitCode();
+            m.visitVarInsn(ALOAD, 0);
+            m.visitMethodInsn(
+                      INVOKESPECIAL
+                    , getInternalName(parent)
+                    , "<init>"
+                    , "()V"
+            );
+            m.visitInsn(RETURN);
+            m.visitEnd();
+            m.visitMaxs(0,0);
+        }
+    }
+
+    /*******************************************************************/
+    protected static String getInternalName(String fullClassName) {
+        return fullClassName.replaceAll("\\.", "/");
+    }
+
+    /*******************************************************************/
+    public T addTargetConstructor(AccessType access) {
+        // AccessType.UNDEF means that the target method isn't defined, so do nothing
+        if (access == AccessType.UNDEF || isInterface(flags) ) {
+            return (T)this;
+        }
+
+        // Add target constructor
+        int methodAccessType = access.value();
+
+        MethodVisitor m =
+                writer.visitMethod(
+                        methodAccessType
+                        , "<init>"
+                        , "(I)V"
+                        , null
+                        , null
+                );
+
+        // Add a call to parent constructor
+        m.visitCode();
+        m.visitVarInsn(ALOAD, 0);
+        m.visitMethodInsn(
+                  INVOKESPECIAL
+                , getInternalName(parentClassName)
+                , "<init>"
+                , "()V"
+        );
+
+        // Add result reporting
+        String shortName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
+        m.visitLdcInsn(shortName+".<init>");
+        m.visitFieldInsn(
+                  PUTSTATIC
+                , "Result"
+                , "value"
+                , "Ljava/lang/String;"
+        );
+
+        m.visitInsn(RETURN);
+        m.visitEnd();
+        m.visitMaxs(0,0);
+
+        return (T)this;
+
+    }
+
+    /*******************************************************************/
+    public T addTargetMethod(AccessType access) {
+        return addTargetMethod(access, 0);
+    }
+
+    /*******************************************************************/
+    public T addTargetMethod(AccessType access, int additionalFlags) {
+        // AccessType.UNDEF means that the target method isn't defined, so do nothing
+        if (access == AccessType.UNDEF) {
+            return (T)this;
+        }
+
+        // Add target method
+        int methodAccessType = access.value();
+        if ( isInterface(flags) || isAbstract(flags) ) {
+            methodAccessType |= ACC_ABSTRACT;
+        }
+
+        // Skip method declaration for abstract private case, which doesn't pass
+        // classfile verification stage
+        if ( isPrivate(methodAccessType) && isAbstract(methodAccessType) ) {
+            return (T)this;
+        }
+
+        MethodVisitor m =
+                writer.visitMethod(
+                        methodAccessType | additionalFlags
+                        , targetMethodName
+                        , "()Ljava/lang/String;"
+                        , null
+                        , null
+                );
+
+        // Don't generate body if the method is abstract
+        if ( (methodAccessType & ACC_ABSTRACT) == 0 ) {
+            String shortName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);
+
+            // Simply returns info about itself
+            m.visitCode();
+            m.visitLdcInsn(shortName+"."+targetMethodName);
+            m.visitInsn(ARETURN);
+            m.visitEnd();
+            m.visitMaxs(0,0);
+        }
+
+        return (T)this;
+    }
+
+    /*******************************************************************/
+    public T addField(int access, String name, String type) {
+        writer.visitField(
+                access
+                , name
+                , getInternalName(type)
+                , null
+                , null
+        )
+                .visitEnd();
+
+        return (T)this;
+    }
+
+    /*******************************************************************/
+    // Add target method call site into current class
+    public T addCaller(String targetClass, int callType) {
+        MethodVisitor m = writer.visitMethod(
+                ACC_PUBLIC | ACC_STATIC
+                , "call"
+                , String.format( "(L%s;)Ljava/lang/String;" , getInternalName(targetClass))
+                , null
+                , null
+        );
+
+        m.visitCode();
+        m.visitVarInsn(ALOAD, 0);
+        m.visitMethodInsn(
+                  callType
+                , getInternalName(targetClass)
+                , targetMethodName
+                , "()Ljava/lang/String;"
+        );
+        m.visitInsn(ARETURN);
+        m.visitEnd();
+        m.visitMaxs(0,0);
+
+        return (T)this;
+    }
+
+    /*******************************************************************/
+    public byte[] getClassFile() {
+        writer.visitEnd();
+        return writer.toByteArray();
+    }
+
+    /*******************************************************************/
+    public String getFullClassName() {
+        return fullClassName;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/InvocationTests/shared/Utils.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package shared;
+
+import java.util.List;
+
+/**
+ * Just a set of constants
+ */
+public class Utils {
+    public static final String TARGET_METHOD_NAME = "m";
+    public static int version = 50;
+
+    public static boolean isACC_SUPER = false;
+
+    public static void init(List<String> args) {
+        for (String param : args) {
+            String name = "classfile_version";
+            String pattern = "--"+name+"=";
+            if (param.startsWith(pattern)) {
+                String value = param.substring(pattern.length());
+                int majorVersion = 50;
+                int minorVersion = 0;
+
+                try {
+                    String[] versions = value.split(":");
+                    if (versions.length > 2) {
+                        throw new RuntimeException(String.format("Unknown %s value: %s", name, value));
+                    }
+
+                    try {
+                        majorVersion = Integer.parseInt(versions[0]);
+                        if (versions.length > 1) {
+                            minorVersion = Integer.parseInt(versions[1]);
+                        }
+                    } catch(Exception e) {
+                        throw new RuntimeException(String.format("Can't parse %s value: '%s'", name, value));
+                    }
+                } catch (Exception e) {
+                    System.out.println("ERROR: "+e.getMessage());
+                }
+
+                version = majorVersion + (minorVersion << 16);
+
+                System.out.printf("INFO: Class file version: major: %d; minor: %d\n", majorVersion, minorVersion);
+
+                if (majorVersion < 49 && !args.contains("--no_acc_super")) {
+                    isACC_SUPER = true;
+                    System.out.printf("INFO: Enabling ACC_SUPER flag for major: %d\nTo disable it, specify --no_acc_super option.\n", majorVersion, minorVersion);
+                }
+            } else if (param.equals("--no_acc_super")){
+                System.out.println("INFO: ACC_SUPER flag is disabled");
+                isACC_SUPER = false;
+            } else if (param.equals("--acc_super")){
+                isACC_SUPER = true;
+            } else {
+                System.out.println("ERROR: Unknown option: "+param);
+                printHelp();
+                System.exit(1);
+            }
+        }
+    }
+
+    public static void printHelp() {
+        System.out.println(
+                 "Supported parameters:\n"
+               + "\t--classfile_version=major_version[:minor_version]\n"
+               + "\t\t- specify class file version for generated classes\n"
+               + "\t--no_acc_super\n"
+               + "\t\t- don't add ACC_SUPER flag into generated classes\n"
+               + "\t--acc_super\n"
+               + "\t\t- force ACC_SUPER flag in generated classes\n"
+               + "\t--dump\n"
+               + "\t\t- dump generated classes\n"
+               + "\t--noexecute\n"
+               + "\t\t- print only expected results, don't execute tests\n"
+        );
+    }
+
+    /*******************************************************************/
+    public static String getInternalName(String s) {
+        return s.replaceAll("\\.", "/");
+    }
+
+}
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,22 @@
             "-Xshare:dump",
             "-showversion", "-Xlog:cds,cds+hashtables"));
 
-        TestCommon.checkDump(TestCommon.executeAndLog(dumpPb, "dump"));
+        boolean continueTest = true;
+        OutputAnalyzer output = TestCommon.executeAndLog(dumpPb, "dump");
+        try {
+            TestCommon.checkDump(output);
+        } catch (java.lang.RuntimeException re) {
+            if (!output.getStdout().contains("UseCompressedOops and UseCompressedClassPointers have been disabled due to")) {
+                throw re;
+            } else {
+                System.out.println("Shared archive was not created due to UseCompressedOops and UseCompressedClassPointers have been disabled.");
+                continueTest = false;
+            }
+        }
+
+        if (!continueTest) {
+            return;
+        }
 
         ProcessBuilder runPb = ProcessTools.createJavaProcessBuilder(true,
           TestCommon.concat(vmOptionsPrefix,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8226709
+ * @summary MethodTypeDesc::resolveConstantDesc needs access check per the specification
+ * @compile ../pkg2/PublicClass.java ../pkg2/NonPublicClass.java
+ * @run main pkg1.MethodTypeDescriptorAccessTest
+ */
+
+package pkg1;
+
+import java.lang.invoke.*;
+import java.lang.invoke.MethodType;
+import java.lang.constant.*;
+
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import static java.lang.invoke.MethodType.*;
+
+public class MethodTypeDescriptorAccessTest {
+    public static void main(String... args) throws Throwable {
+        new MethodTypeDescriptorAccessTest().test();
+    }
+
+    void test() {
+        Lookup selfLookup = MethodHandles.lookup();
+        //first test PublicClass
+        String descriptorpub = "(Lpkg2/PublicClass;)Lpkg2/PublicClass;";
+        MethodTypeDesc mtdpub = MethodTypeDesc.ofDescriptor(descriptorpub);
+        checkValidAccess(mtdpub, selfLookup);
+
+        // test NonPublicClass in the return type
+        String descriptornp = "()Lpkg2/NonPublicClass;";
+        MethodTypeDesc mtdnp = MethodTypeDesc.ofDescriptor(descriptornp);
+        checkInvalidAccess(mtdnp, selfLookup);
+
+        // test NonPublicClass in the parameters
+        descriptornp = "(Lpkg2/NonPublicClass;)I";
+        mtdnp = MethodTypeDesc.ofDescriptor(descriptornp);
+        checkInvalidAccess(mtdnp, selfLookup);
+
+        MethodType mt = MethodType.fromMethodDescriptorString("(Lpkg2/NonPublicClass;)I", selfLookup.lookupClass().getClassLoader());
+    }
+
+    private void checkValidAccess(MethodTypeDesc mtd, Lookup lookup) {
+        try {
+            MethodType mt = (MethodType)mtd.resolveConstantDesc(lookup);
+        } catch (ReflectiveOperationException unexpected) {
+            throw new Error("resolveConstantDesc() threw ReflectiveOperationException unexpectedly with cause " +
+                    unexpected.getCause() + " for " + mtd);
+        }
+    }
+
+    private void checkInvalidAccess(MethodTypeDesc mtd, Lookup lookup) {
+        try {
+            MethodType mt = (MethodType)mtd.resolveConstantDesc(lookup);
+            throw new Error("resolveConstantDesc() succeeded unexpectedly " + mtd);
+        } catch (ReflectiveOperationException expected) {
+            if (expected.getClass() != IllegalAccessException.class) {
+                throw new Error("resolveConstantDesc() threw unexpected ReflectiveOperationException with cause " +
+                        expected.getCause() + " for " + mtd);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/constant/access_test/pkg2/NonPublicClass.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package pkg2;
+
+class NonPublicClass {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/constant/access_test/pkg2/PublicClass.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package pkg2;
+
+public class PublicClass {}
--- a/test/jdk/java/net/Socket/SetSoLinger.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/java/net/Socket/SetSoLinger.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
  * @summary Test Socket.setSoLinger
  * @run main SetSoLinger
  * @run main/othervm -Djava.net.preferIPv4Stack=true SetSoLinger
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true SetSoLinger
  */
 
 import java.net.*;
@@ -41,7 +42,10 @@
 
         int value;
         InetAddress addr = InetAddress.getLocalHost();
-        ServerSocket ss = new ServerSocket(0);
+        ServerSocket ss = new ServerSocket();
+
+        InetSocketAddress socketAddress = new InetSocketAddress(addr, 0);
+        ss.bind(socketAddress);
         int port = ss.getLocalPort();
 
         Socket s = new Socket(addr, port);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/swing/LookAndFeel/SystemLookAndFeel/SystemLookAndFeelTest.java	Fri Jun 28 14:36:42 2019 +0530
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8226783
+ * @key headful
+ * @summary Verify System L&F
+ */
+
+/*
+ * Verify the System LAF is what we expect based on platform and,
+ * in at least one case, the desktop environment.
+ * Since changes to the system LAF are a once in a blue moon event,
+ * this test is useful to tell us of unexpected problems.
+ * Note: this test must be run in a headful environment
+ * since otherwise a system LAF may not be available.
+ */
+
+public class SystemLookAndFeelTest {
+
+    public static void main(String[] args) {
+
+        String laf = javax.swing.UIManager.getSystemLookAndFeelClassName();
+        String os = System.getProperty("os.name").toLowerCase();
+        System.out.println("OS is " + os);
+        System.out.println("Reported System LAF is " + laf);
+
+        String expLAF = null;
+        if (os.contains("windows")) {
+            expLAF = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+        } else if (os.contains("macos")) {
+            expLAF = "com.apple.laf.AquaLookAndFeel";
+        } else if (os.contains("linux") || os.contains("sunos")) {
+           /*
+            * The implementation keys off the following desktop setting to
+            * decide if GTK is an appropriate system L&F.
+            * In its absence, there probably isn't support for the GTK L&F
+            * anyway. It does not tell us if the GTK libraries are available
+            * but they really should be if this is a gnome session.
+            * If it proves necessary the test can perhaps be updated to see
+            * if the GTK LAF is listed as installed and can be instantiated.
+            */
+           String gnome = System.getenv("GNOME_DESKTOP_SESSION_ID");
+           System.out.println("Gnome desktop session ID is " + gnome);
+           if (gnome != null) {
+               expLAF = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
+           } else if (os.contains("linux")) {
+               expLAF = "javax.swing.plaf.metal.MetalLookAndFeel";
+           } else if (os.contains("sunos")) {
+               expLAF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
+           }
+       }
+        System.out.println("Expected System LAF is " + expLAF);
+        if (expLAF == null) {
+            System.out.println("No match for expected LAF, unknown OS ?");
+            return;
+        }
+        if (!(laf.equals(expLAF))) {
+            throw new RuntimeException("LAF not as expected");
+        }
+   }
+}
--- a/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/jdk/jfr/event/gc/collection/TestG1ParallelPhases.java	Fri Jun 28 14:36:42 2019 +0530
@@ -100,20 +100,30 @@
             "CMRefRoots",
             "WaitForStrongCLD",
             "WeakCLDRoots",
-            "UpdateRS",
-            "ScanHCC",
-            "ScanRS",
+            "MergeHCC",
+            "MergeRS",
+            "MergeLB",
+            "ScanHR",
             "CodeRoots",
             "ObjCopy",
             "Termination",
             "StringDedupQueueFixup",
             "StringDedupTableFixup",
             "RedirtyCards",
-       //     "PreserveCMReferents",
             "NonYoungFreeCSet",
             "YoungFreeCSet"
         );
 
+        // Some GC phases may or may not occur depending on environment. Filter them out
+        // since we can not reliably guarantee that they occur (or not).
+        Set<String> optPhases = of(
+            "OptScanHR",
+            "OptMergeRS",
+            "OptCodeRoots",
+            "OptObjCopy"
+        );
+        usedPhases.removeAll(optPhases);
+
         assertTrue(usedPhases.equals(allPhases), "Compare events expected and received"
             + ", Not found phases: " + allPhases.stream().filter(p -> !usedPhases.contains(p)).collect(joining(", "))
             + ", Not expected phases: " + usedPhases.stream().filter(p -> !allPhases.contains(p)).collect(joining(", ")));
--- a/test/jdk/sun/net/www/protocol/http/AsyncDisconnect.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/AsyncDisconnect.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,18 +24,21 @@
 /*
  * @test
  * @bug 6358532
+ * @library /test/lib
  * @modules jdk.httpserver
  * @run main/othervm AsyncDisconnect
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true AsyncDisconnect
  * @summary HttpURLConnection.disconnect doesn't really do the job
  */
 
 import java.net.*;
-import java.util.*;
 import java.io.*;
 import com.sun.net.httpserver.*;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 
+import jdk.test.lib.net.URIBuilder;
+
 public class AsyncDisconnect implements Runnable
 {
     com.sun.net.httpserver.HttpServer httpServer;
@@ -43,27 +46,30 @@
     ExecutorService executorService;
     HttpURLConnection uc;
 
-    public static void main(String[] args) {
+    public static void main(String[] args) throws Exception {
         new AsyncDisconnect();
     }
 
-    public AsyncDisconnect() {
-        try {
-            startHttpServer();
-            doClient();
-        } catch (IOException ioe) {
-            System.err.println(ioe);
-        }
+    public AsyncDisconnect() throws Exception {
+        startHttpServer();
+        doClient();
     }
 
-    void doClient() {
+    void doClient() throws Exception {
+        Thread t = new Thread(this);
+
         try {
             InetSocketAddress address = httpServer.getAddress();
-            URL url = new URL("http://" + address.getHostName() + ":" + address.getPort() + "/test/");
-            uc = (HttpURLConnection)url.openConnection();
+            URL url = URIBuilder.newBuilder()
+                    .scheme("http")
+                    .host(address.getAddress())
+                    .port(address.getPort())
+                    .path("/test/")
+                    .toURL();
+            uc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
 
             // create a thread that will disconnect the connection
-            (new Thread(this)).start();
+            t.start();
 
             uc.getInputStream();
 
@@ -73,11 +79,11 @@
         } catch (SocketException se) {
             // this is what we expect to happen and is OK.
             //System.out.println(se);
-        } catch (IOException e) {
-            e.printStackTrace();
         } finally {
             httpServer.stop(1);
+            t.join();
             executorService.shutdown();
+
         }
     }
 
@@ -93,7 +99,9 @@
      * Http Server
      */
     public void startHttpServer() throws IOException {
-        httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0);
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, 0);
+        httpServer = com.sun.net.httpserver.HttpServer.create(address, 0);
         httpHandler = new MyHandler();
 
         HttpContext ctx = httpServer.createContext("/test/", httpHandler);
--- a/test/jdk/sun/net/www/protocol/http/B6641309.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/B6641309.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,10 @@
  * @test
  * @bug 6641309
  * @modules jdk.httpserver
- * @summary Wrong Cookie separator used in HttpURLConnection
+ * @library /test/lib
+ * @run main/othervm B6641309
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true B6641309
+ * @summary Wrong Cookie separator used in HttpURLConnection B6641309
  */
 
 import java.net.*;
@@ -35,65 +38,65 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 
+import jdk.test.lib.net.URIBuilder;
+
 public class B6641309
 {
     com.sun.net.httpserver.HttpServer httpServer;
     ExecutorService executorService;
 
-    public static void main(String[] args)
-    {
+    public static void main(String[] args) throws Exception {
         new B6641309();
     }
 
-    public B6641309()
-    {
-        try {
-            startHttpServer();
-            doClient();
-        } catch (IOException ioe) {
-            System.err.println(ioe);
-        }
+    public B6641309() throws Exception {
+        startHttpServer();
+        doClient();
     }
 
-    void doClient() {
+    void doClient() throws Exception {
         CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
-        try {
-            InetSocketAddress address = httpServer.getAddress();
+        ProxySelector.setDefault(ProxySelector.of(null));
+
+        InetSocketAddress address = httpServer.getAddress();
 
-            // GET Request
-            URL url = new URL("http://localhost:" + address.getPort() + "/test/");
-            CookieHandler ch = CookieHandler.getDefault();
-            Map<String,List<String>> header = new HashMap<String,List<String>>();
-            List<String> values = new LinkedList<String>();
-            values.add("Test1Cookie=TEST1; path=/test/");
-            values.add("Test2Cookie=TEST2; path=/test/");
-            header.put("Set-Cookie", values);
+        // GET Request
+        URL url = URIBuilder.newBuilder()
+                .scheme("http")
+                .host(address.getAddress())
+                .port(address.getPort())
+                .path("/test/")
+                .toURL();
 
-            // preload the CookieHandler with a cookie for our URL
-            // so that it will be sent during the first request
-            ch.put(url.toURI(), header);
-            HttpURLConnection uc = (HttpURLConnection)url.openConnection();
-            int resp = uc.getResponseCode();
-            if (resp != 200)
-                throw new RuntimeException("Failed: Response code from GET is not 200");
+        CookieHandler ch = CookieHandler.getDefault();
+        Map<String,List<String>> header = new HashMap<String,List<String>>();
+        List<String> values = new LinkedList<String>();
+        values.add("Test1Cookie=TEST1; path=/test/");
+        values.add("Test2Cookie=TEST2; path=/test/");
+        header.put("Set-Cookie", values);
 
-            System.out.println("Response code from GET = 200 OK");
+        // preload the CookieHandler with a cookie for our URL
+        // so that it will be sent during the first request
+        ch.put(url.toURI(), header);
+        HttpURLConnection uc = (HttpURLConnection)url.openConnection();
+        int resp = uc.getResponseCode();
+        if (resp != 200) {
+            throw new RuntimeException("Failed: Response code from GET is not 200: "
+                    + resp);
+        }
+        System.out.println("Response code from GET = 200 OK");
 
-        } catch (IOException e) {
-            e.printStackTrace();
-        } catch (URISyntaxException e) {
-            e.printStackTrace();
-        } finally {
-            httpServer.stop(1);
-            executorService.shutdown();
-        }
+        httpServer.stop(1);
+        executorService.shutdown();
     }
 
     /**
      * Http Server
      */
     public void startHttpServer() throws IOException {
-        httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0);
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, 0);
+        httpServer = com.sun.net.httpserver.HttpServer.create(address, 0);
 
         // create HttpServer context
         HttpContext ctx = httpServer.createContext("/test/", new MyHandler());
--- a/test/jdk/sun/net/www/protocol/http/B6660405.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/B6660405.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,10 @@
  * @test
  * @bug 6660405
  * @modules jdk.httpserver
- * @summary HttpURLConnection returns the wrong InputStream
+ * @library /test/lib
+ * @run main/othervm B6660405
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true B6660405
+ * @summary HttpURLConnection returns the wrong InputStream B6660405
  */
 
 import java.net.*;
@@ -34,6 +37,8 @@
 import com.sun.net.httpserver.*;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
+import jdk.test.lib.net.URIBuilder;
+
 
 public class B6660405
 {
@@ -72,7 +77,8 @@
         }
 
         @Override
-        public CacheResponse get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders) throws IOException
+        public CacheResponse get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders)
+                throws IOException
         {
             if (uri.getPath().equals("/redirect/index.html")) {
                 return new MyCacheResponse();
@@ -88,53 +94,61 @@
 
     }
 
-    public static void main(String[] args)
+    public static void main(String[] args) throws Exception
     {
         new B6660405();
     }
 
-    public B6660405()
-    {
-        try {
-            startHttpServer();
-            doClient();
-        } catch (IOException ioe) {
-            System.err.println(ioe);
-        }
+    public B6660405() throws Exception {
+        startHttpServer();
+        doClient();
     }
 
-    void doClient() {
+    void doClient() throws Exception {
         ResponseCache.setDefault(new MyResponseCache());
-        try {
-            InetSocketAddress address = httpServer.getAddress();
+        InetSocketAddress address = httpServer.getAddress();
+
+        // GET Request
+        URL url = URIBuilder.newBuilder()
+                .scheme("http")
+                .host(address.getAddress())
+                .port(address.getPort())
+                .path("/test/index.html")
+                .toURL();
 
-            // GET Request
-            URL url = new URL("http://localhost:" + address.getPort() + "/test/index.html");
-            HttpURLConnection uc = (HttpURLConnection)url.openConnection();
-            int code = uc.getResponseCode();
-            System.err.println("response code = " + code);
-            int l = uc.getContentLength();
-            System.err.println("content-length = " + l);
-            InputStream in = uc.getInputStream();
-            int i = 0;
-            // Read till end of stream
-            do {
-                i = in.read();
-            } while (i != -1);
-            in.close();
-        } catch (IOException e) {
-            throw new RuntimeException("Got the wrong InputStream after checking headers");
-        } finally {
-            httpServer.stop(1);
-            executorService.shutdown();
+        HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+        int code = uc.getResponseCode();
+        System.err.println("response code = " + code);
+        int l = uc.getContentLength();
+        System.err.println("content-length = " + l);
+        if (l != 1024) {
+            throw new AssertionError("Bad content length: " + l);
         }
+
+        InputStream in = uc.getInputStream();
+        int i = 0;
+        // Read till end of stream
+        do {
+            l--;
+            i = in.read();
+        } while (i != -1);
+        in.close();
+        if (l != -1) {
+            throw new AssertionError("Only " + (1024 - (l + 1))
+                    + " bytes read from stream.");
+        }
+
+        httpServer.stop(1);
+        executorService.shutdown();
     }
 
     /**
      * Http Server
      */
     public void startHttpServer() throws IOException {
-        httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0);
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback,0);
+        httpServer = com.sun.net.httpserver.HttpServer.create(address, 0);
 
         // create HttpServer context
         HttpContext ctx = httpServer.createContext("/test/", new MyHandler());
--- a/test/jdk/sun/net/www/protocol/http/B6890349.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/B6890349.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,9 @@
 /**
  * @test
  * @bug 6890349
+ * @library /test/lib
  * @run main/othervm B6890349
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true B6890349
  * @summary  Light weight HTTP server
  */
 
@@ -34,7 +36,11 @@
     public static final void main(String[] args) throws Exception {
 
         try {
-            ServerSocket server = new ServerSocket (0);
+            ServerSocket server = new ServerSocket();
+            InetAddress loopback = InetAddress.getLoopbackAddress();
+            InetSocketAddress address = new InetSocketAddress(loopback, 0);
+            server.bind(address);
+
             int port = server.getLocalPort();
             System.out.println ("listening on "  + port);
             B6890349 t = new B6890349 (server);
@@ -44,11 +50,11 @@
                 port,
                 "/foo\nbar");
             System.out.println("URL: " + u);
-            HttpURLConnection urlc = (HttpURLConnection)u.openConnection ();
+            HttpURLConnection urlc = (HttpURLConnection)u.openConnection(Proxy.NO_PROXY);
             InputStream is = urlc.getInputStream();
             throw new RuntimeException ("Test failed");
         } catch (IOException e) {
-            System.out.println ("OK");
+            System.out.println ("Caught expected exception: " + e);
         }
     }
 
--- a/test/jdk/sun/net/www/protocol/http/Modified.java	Wed Jun 26 14:28:47 2019 +0530
+++ b/test/jdk/sun/net/www/protocol/http/Modified.java	Fri Jun 28 14:36:42 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,12 +24,16 @@
 /*
  * @test
  * @bug 4092605
+ * @library /test/lib
+ * @run main/othervm Modified
+ * @run main/othervm -Djava.net.preferIPv6Addresses=true Modified
  * @summary Test HttpURLConnection setIfModifiedSince
  *
  */
 
 import java.net.*;
 import java.io.*;
+import jdk.test.lib.net.URIBuilder;
 
 public class Modified implements Runnable {
 
@@ -78,13 +82,22 @@
 
     Modified() throws Exception {
 
-        ss = new ServerSocket(0);
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, 0);
+        ss = new ServerSocket();
+        ss.bind(address);
+        int port = ss.getLocalPort();
+
         Thread thr = new Thread(this);
         thr.start();
 
-        URL testURL = new URL("http://localhost:" + ss.getLocalPort() +
-                              "/index.html");
-        URLConnection URLConn = testURL.openConnection();
+        URL testURL = URIBuilder.newBuilder()
+                .scheme("http")
+                .host(loopback)
+                .port(port)
+                .path("/index.html")
+                .toURL();
+        URLConnection URLConn = testURL.openConnection(Proxy.NO_PROXY);
         HttpURLConnection httpConn;
 
         if (URLConn instanceof HttpURLConnection) {