changeset 59272:8081bf6f4309

Merge
author psadhukhan
date Tue, 03 Dec 2019 12:45:47 +0530
parents fe5e931830e5 9eaef94e74b5
children e26c3e28f6f0
files src/hotspot/share/gc/g1/survRateGroup.cpp src/hotspot/share/gc/g1/survRateGroup.hpp src/java.base/share/classes/java/time/overview.html src/jdk.compiler/share/classes/META-INF/services/com.sun.tools.javac.platform.PlatformProvider src/jdk.compiler/share/classes/com/sun/tools/javac/services/javax.tools.JavaCompilerTool
diffstat 54 files changed, 931 insertions(+), 899 deletions(-) [+]
line wrap: on
line diff
--- a/make/langtools/tools/propertiesparser/resources/templates.properties	Mon Dec 02 16:38:34 2019 -0800
+++ b/make/langtools/tools/propertiesparser/resources/templates.properties	Tue Dec 03 12:45:47 2019 +0530
@@ -1,3 +1,28 @@
+#
+# 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
+# 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.
+#
+# 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.
+#
+
 toplevel.decl=\
     package {0};\n\
     \n\
--- a/src/hotspot/share/code/nmethod.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/code/nmethod.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1565,14 +1565,18 @@
 // Transfer information from compilation to jvmti
 void nmethod::post_compiled_method_load_event() {
 
-  Method* moop = method();
+ // This is a bad time for a safepoint.  We don't want
+ // this nmethod to get unloaded while we're queueing the event.
+ NoSafepointVerifier nsv;
+
+  Method* m = method();
   HOTSPOT_COMPILED_METHOD_LOAD(
-      (char *) moop->klass_name()->bytes(),
-      moop->klass_name()->utf8_length(),
-      (char *) moop->name()->bytes(),
-      moop->name()->utf8_length(),
-      (char *) moop->signature()->bytes(),
-      moop->signature()->utf8_length(),
+      (char *) m->klass_name()->bytes(),
+      m->klass_name()->utf8_length(),
+      (char *) m->name()->bytes(),
+      m->name()->utf8_length(),
+      (char *) m->signature()->bytes(),
+      m->signature()->utf8_length(),
       insts_begin(), insts_size());
 
   if (JvmtiExport::should_post_compiled_method_load() ||
--- a/src/hotspot/share/gc/g1/g1Analytics.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1Analytics.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -125,16 +125,16 @@
   return seq->num() >= 3;
 }
 
-double G1Analytics::get_new_unit_prediction(TruncatedSeq const* seq) const {
-  return _predictor->get_new_unit_prediction(seq);
+double G1Analytics::predict_in_unit_interval(TruncatedSeq const* seq) const {
+  return _predictor->predict_in_unit_interval(seq);
 }
 
-size_t G1Analytics::get_new_size_prediction(TruncatedSeq const* seq) const {
-  return (size_t)get_new_lower_zero_bound_prediction(seq);
+size_t G1Analytics::predict_size(TruncatedSeq const* seq) const {
+  return (size_t)predict_zero_bounded(seq);
 }
 
-double G1Analytics::get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const {
-  return _predictor->get_new_lower_zero_bound_prediction(seq);
+double G1Analytics::predict_zero_bounded(TruncatedSeq const* seq) const {
+  return _predictor->predict_zero_bounded(seq);
 }
 
 int G1Analytics::num_alloc_rate_ms() const {
@@ -229,50 +229,50 @@
 }
 
 double G1Analytics::predict_alloc_rate_ms() const {
-  return get_new_lower_zero_bound_prediction(_alloc_rate_ms_seq);
+  return predict_zero_bounded(_alloc_rate_ms_seq);
 }
 
 double G1Analytics::predict_concurrent_refine_rate_ms() const {
-  return get_new_lower_zero_bound_prediction(_concurrent_refine_rate_ms_seq);
+  return predict_zero_bounded(_concurrent_refine_rate_ms_seq);
 }
 
 double G1Analytics::predict_logged_cards_rate_ms() const {
-  return get_new_lower_zero_bound_prediction(_logged_cards_rate_ms_seq);
+  return predict_zero_bounded(_logged_cards_rate_ms_seq);
 }
 
 double G1Analytics::predict_young_card_merge_to_scan_ratio() const {
-  return get_new_unit_prediction(_young_card_merge_to_scan_ratio_seq);
+  return predict_in_unit_interval(_young_card_merge_to_scan_ratio_seq);
 }
 
 size_t G1Analytics::predict_scan_card_num(size_t rs_length, bool for_young_gc) const {
   if (for_young_gc || !enough_samples_available(_mixed_card_merge_to_scan_ratio_seq)) {
     return (size_t)(rs_length * predict_young_card_merge_to_scan_ratio());
   } else {
-    return (size_t)(rs_length * get_new_unit_prediction(_mixed_card_merge_to_scan_ratio_seq));
+    return (size_t)(rs_length * predict_in_unit_interval(_mixed_card_merge_to_scan_ratio_seq));
   }
 }
 
 double G1Analytics::predict_card_merge_time_ms(size_t card_num, bool for_young_gc) const {
   if (for_young_gc || !enough_samples_available(_mixed_cost_per_card_merge_ms_seq)) {
-    return card_num * get_new_lower_zero_bound_prediction(_young_cost_per_card_merge_ms_seq);
+    return card_num * predict_zero_bounded(_young_cost_per_card_merge_ms_seq);
   } else {
-    return card_num * get_new_lower_zero_bound_prediction(_mixed_cost_per_card_merge_ms_seq);
+    return card_num * predict_zero_bounded(_mixed_cost_per_card_merge_ms_seq);
   }
 }
 
 double G1Analytics::predict_card_scan_time_ms(size_t card_num, bool for_young_gc) const {
   if (for_young_gc || !enough_samples_available(_mixed_cost_per_card_scan_ms_seq)) {
-    return card_num * get_new_lower_zero_bound_prediction(_young_cost_per_card_scan_ms_seq);
+    return card_num * predict_zero_bounded(_young_cost_per_card_scan_ms_seq);
   } else {
-    return card_num * get_new_lower_zero_bound_prediction(_mixed_cost_per_card_scan_ms_seq);
+    return card_num * predict_zero_bounded(_mixed_cost_per_card_scan_ms_seq);
   }
 }
 
 double G1Analytics::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const {
   if (!enough_samples_available(_cost_per_byte_ms_during_cm_seq)) {
-    return (1.1 * bytes_to_copy) * get_new_lower_zero_bound_prediction(_copy_cost_per_byte_ms_seq);
+    return (1.1 * bytes_to_copy) * predict_zero_bounded(_copy_cost_per_byte_ms_seq);
   } else {
-    return bytes_to_copy * get_new_lower_zero_bound_prediction(_cost_per_byte_ms_during_cm_seq);
+    return bytes_to_copy * predict_zero_bounded(_cost_per_byte_ms_during_cm_seq);
   }
 }
 
@@ -280,36 +280,36 @@
   if (during_concurrent_mark) {
     return predict_object_copy_time_ms_during_cm(bytes_to_copy);
   } else {
-    return bytes_to_copy * get_new_lower_zero_bound_prediction(_copy_cost_per_byte_ms_seq);
+    return bytes_to_copy * predict_zero_bounded(_copy_cost_per_byte_ms_seq);
   }
 }
 
 double G1Analytics::predict_constant_other_time_ms() const {
-  return get_new_lower_zero_bound_prediction(_constant_other_time_ms_seq);
+  return predict_zero_bounded(_constant_other_time_ms_seq);
 }
 
 double G1Analytics::predict_young_other_time_ms(size_t young_num) const {
-  return young_num * get_new_lower_zero_bound_prediction(_young_other_cost_per_region_ms_seq);
+  return young_num * predict_zero_bounded(_young_other_cost_per_region_ms_seq);
 }
 
 double G1Analytics::predict_non_young_other_time_ms(size_t non_young_num) const {
-  return non_young_num * get_new_lower_zero_bound_prediction(_non_young_other_cost_per_region_ms_seq);
+  return non_young_num * predict_zero_bounded(_non_young_other_cost_per_region_ms_seq);
 }
 
 double G1Analytics::predict_remark_time_ms() const {
-  return get_new_lower_zero_bound_prediction(_concurrent_mark_remark_times_ms);
+  return predict_zero_bounded(_concurrent_mark_remark_times_ms);
 }
 
 double G1Analytics::predict_cleanup_time_ms() const {
-  return get_new_lower_zero_bound_prediction(_concurrent_mark_cleanup_times_ms);
+  return predict_zero_bounded(_concurrent_mark_cleanup_times_ms);
 }
 
 size_t G1Analytics::predict_rs_length() const {
-  return get_new_size_prediction(_rs_length_seq) + get_new_size_prediction(_rs_length_diff_seq);
+  return predict_size(_rs_length_seq) + predict_size(_rs_length_diff_seq);
 }
 
 size_t G1Analytics::predict_pending_cards() const {
-  return get_new_size_prediction(_pending_cards_seq);
+  return predict_size(_pending_cards_seq);
 }
 
 double G1Analytics::last_known_gc_end_time_sec() const {
--- a/src/hotspot/share/gc/g1/g1Analytics.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1Analytics.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -84,9 +84,9 @@
   // The constant used is random but "small".
   bool enough_samples_available(TruncatedSeq const* seq) const;
 
-  double get_new_unit_prediction(TruncatedSeq const* seq) const;
-  size_t get_new_size_prediction(TruncatedSeq const* seq) const;
-  double get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const;
+  double predict_in_unit_interval(TruncatedSeq const* seq) const;
+  size_t predict_size(TruncatedSeq const* seq) const;
+  double predict_zero_bounded(TruncatedSeq const* seq) const;
 
 public:
   G1Analytics(const G1Predictions* predictor);
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -4266,7 +4266,7 @@
     HeapRegion* r = g1h->region_at(region_idx);
     assert(!g1h->is_on_master_free_list(r), "sanity");
 
-    Atomic::add(&_rs_length, r->rem_set()->occupied_locked());
+    Atomic::add(&_rs_length, r->rem_set()->occupied());
 
     if (!is_young) {
       g1h->hot_card_cache()->reset_card_counts(r);
--- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -39,7 +39,7 @@
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/quickSort.hpp"
 
-G1CollectorState* G1CollectionSet::collector_state() {
+G1CollectorState* G1CollectionSet::collector_state() const {
   return _g1h->collector_state();
 }
 
@@ -47,8 +47,8 @@
   return _policy->phase_times();
 }
 
-double G1CollectionSet::predict_region_elapsed_time_ms(HeapRegion* hr) {
-  return _policy->predict_region_elapsed_time_ms(hr, collector_state()->in_young_only_phase());
+double G1CollectionSet::predict_region_non_copy_time_ms(HeapRegion* hr) const {
+  return _policy->predict_region_non_copy_time_ms(hr, collector_state()->in_young_only_phase());
 }
 
 G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
@@ -66,15 +66,17 @@
   _recorded_rs_length(0),
   _inc_build_state(Inactive),
   _inc_part_start(0),
+  _inc_collection_set_stats(NULL),
   _inc_bytes_used_before(0),
   _inc_recorded_rs_length(0),
   _inc_recorded_rs_length_diff(0),
-  _inc_predicted_elapsed_time_ms(0.0),
-  _inc_predicted_elapsed_time_ms_diff(0.0) {
+  _inc_predicted_non_copy_time_ms(0.0),
+  _inc_predicted_non_copy_time_ms_diff(0.0) {
 }
 
 G1CollectionSet::~G1CollectionSet() {
   FREE_C_HEAP_ARRAY(uint, _collection_set_regions);
+  FREE_C_HEAP_ARRAY(IncCollectionSetRegionStat, _inc_collection_set_stats);
   free_optional_regions();
   clear_candidates();
 }
@@ -97,6 +99,7 @@
   guarantee(_collection_set_regions == NULL, "Must only initialize once.");
   _collection_set_max_length = max_region_length;
   _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
+  _inc_collection_set_stats = NEW_C_HEAP_ARRAY(IncCollectionSetRegionStat, max_region_length, mtGC);
 }
 
 void G1CollectionSet::free_optional_regions() {
@@ -145,13 +148,18 @@
 void G1CollectionSet::start_incremental_building() {
   assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
   assert(_inc_build_state == Inactive, "Precondition");
+#ifdef ASSERT
+  for (size_t i = 0; i < _collection_set_max_length; i++) {
+    _inc_collection_set_stats[i].reset();
+  }
+#endif
 
   _inc_bytes_used_before = 0;
 
   _inc_recorded_rs_length = 0;
   _inc_recorded_rs_length_diff = 0;
-  _inc_predicted_elapsed_time_ms = 0.0;
-  _inc_predicted_elapsed_time_ms_diff = 0.0;
+  _inc_predicted_non_copy_time_ms = 0.0;
+  _inc_predicted_non_copy_time_ms_diff = 0.0;
 
   update_incremental_marker();
 }
@@ -161,31 +169,17 @@
   assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
 
   // The two "main" fields, _inc_recorded_rs_length and
-  // _inc_predicted_elapsed_time_ms, are updated by the thread
+  // _inc_predicted_non_copy_time_ms, are updated by the thread
   // that adds a new region to the CSet. Further updates by the
   // concurrent refinement thread that samples the young RSet lengths
   // are accumulated in the *_diff fields. Here we add the diffs to
   // the "main" fields.
 
-  if (_inc_recorded_rs_length_diff >= 0) {
-    _inc_recorded_rs_length += _inc_recorded_rs_length_diff;
-  } else {
-    // This is defensive. The diff should in theory be always positive
-    // as RSets can only grow between GCs. However, given that we
-    // sample their size concurrently with other threads updating them
-    // it's possible that we might get the wrong size back, which
-    // could make the calculations somewhat inaccurate.
-    size_t diffs = (size_t) (-_inc_recorded_rs_length_diff);
-    if (_inc_recorded_rs_length >= diffs) {
-      _inc_recorded_rs_length -= diffs;
-    } else {
-      _inc_recorded_rs_length = 0;
-    }
-  }
-  _inc_predicted_elapsed_time_ms += _inc_predicted_elapsed_time_ms_diff;
+  _inc_recorded_rs_length += _inc_recorded_rs_length_diff;
+  _inc_predicted_non_copy_time_ms += _inc_predicted_non_copy_time_ms_diff;
 
   _inc_recorded_rs_length_diff = 0;
-  _inc_predicted_elapsed_time_ms_diff = 0.0;
+  _inc_predicted_non_copy_time_ms_diff = 0.0;
 }
 
 void G1CollectionSet::clear() {
@@ -252,26 +246,23 @@
   assert(hr->is_young(), "Precondition");
   assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint");
 
-  // We could have updated _inc_recorded_rs_length and
-  // _inc_predicted_elapsed_time_ms directly but we'd need to do
-  // that atomically, as this code is executed by a concurrent
-  // refinement thread, potentially concurrently with a mutator thread
-  // allocating a new region and also updating the same fields. To
-  // avoid the atomic operations we accumulate these updates on two
-  // separate fields (*_diff) and we'll just add them to the "main"
-  // fields at the start of a GC.
+  IncCollectionSetRegionStat* stat = &_inc_collection_set_stats[hr->hrm_index()];
 
-  ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length();
-  ssize_t rs_length_diff = (ssize_t) new_rs_length - old_rs_length;
+  size_t old_rs_length = stat->_rs_length;
+  assert(old_rs_length <= new_rs_length,
+         "Remembered set decreased (changed from " SIZE_FORMAT " to " SIZE_FORMAT " region %u type %s)",
+         old_rs_length, new_rs_length, hr->hrm_index(), hr->get_short_type_str());
+  size_t rs_length_diff = new_rs_length - old_rs_length;
+  stat->_rs_length = new_rs_length;
   _inc_recorded_rs_length_diff += rs_length_diff;
 
-  double old_elapsed_time_ms = hr->predicted_elapsed_time_ms();
-  double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr);
-  double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms;
-  _inc_predicted_elapsed_time_ms_diff += elapsed_ms_diff;
+  double old_non_copy_time = stat->_non_copy_time_ms;
+  assert(old_non_copy_time >= 0.0, "Non copy time for region %u not initialized yet, is %.3f", hr->hrm_index(), old_non_copy_time);
+  double new_non_copy_time = predict_region_non_copy_time_ms(hr);
+  double non_copy_time_ms_diff = new_non_copy_time - old_non_copy_time;
 
-  hr->set_recorded_rs_length(new_rs_length);
-  hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms);
+  stat->_non_copy_time_ms = new_non_copy_time;
+  _inc_predicted_non_copy_time_ms_diff += non_copy_time_ms_diff;
 }
 
 void G1CollectionSet::add_young_region_common(HeapRegion* hr) {
@@ -296,30 +287,31 @@
 
   if (!_g1h->collector_state()->in_full_gc()) {
     size_t rs_length = hr->rem_set()->occupied();
-    double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr);
+    double non_copy_time = predict_region_non_copy_time_ms(hr);
 
     // Cache the values we have added to the aggregated information
     // in the heap region in case we have to remove this region from
     // the incremental collection set, or it is updated by the
     // rset sampling code
-    hr->set_recorded_rs_length(rs_length);
-    hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms);
+
+    IncCollectionSetRegionStat* stat = &_inc_collection_set_stats[hr->hrm_index()];
+    stat->_rs_length = rs_length;
+    stat->_non_copy_time_ms = non_copy_time;
 
     _inc_recorded_rs_length += rs_length;
-    _inc_predicted_elapsed_time_ms += region_elapsed_time_ms;
+    _inc_predicted_non_copy_time_ms += non_copy_time;
     _inc_bytes_used_before += hr->used();
   }
 
   assert(!hr->in_collection_set(), "invariant");
   _g1h->register_young_region_with_region_attr(hr);
 
-  size_t collection_set_length = _collection_set_cur_length;
   // We use UINT_MAX as "invalid" marker in verification.
-  assert(collection_set_length < (UINT_MAX - 1),
-         "Collection set is too large with " SIZE_FORMAT " entries", collection_set_length);
-  hr->set_young_index_in_cset((uint)collection_set_length + 1);
+  assert(_collection_set_cur_length < (UINT_MAX - 1),
+         "Collection set is too large with " SIZE_FORMAT " entries", _collection_set_cur_length);
+  hr->set_young_index_in_cset((uint)_collection_set_cur_length + 1);
 
-  _collection_set_regions[collection_set_length] = hr->hrm_index();
+  _collection_set_regions[_collection_set_cur_length] = hr->hrm_index();
   // Concurrent readers must observe the store of the value in the array before an
   // update to the length field.
   OrderAccess::storestore();
@@ -341,21 +333,19 @@
 class G1VerifyYoungAgesClosure : public HeapRegionClosure {
 public:
   bool _valid;
-public:
+
   G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { }
 
   virtual bool do_heap_region(HeapRegion* r) {
     guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str());
 
-    SurvRateGroup* group = r->surv_rate_group();
-
-    if (group == NULL) {
-      log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
+    if (!r->has_surv_rate_group()) {
+      log_error(gc, verify)("## encountered young region without surv_rate_group");
       _valid = false;
     }
 
-    if (r->age_in_surv_rate_group() < 0) {
-      log_error(gc, verify)("## encountered negative age in young region");
+    if (!r->has_valid_age_in_surv_rate()) {
+      log_error(gc, verify)("## encountered invalid age in young region");
       _valid = false;
     }
 
@@ -390,7 +380,7 @@
                   HR_FORMAT_PARAMS(r),
                   p2i(r->prev_top_at_mark_start()),
                   p2i(r->next_top_at_mark_start()),
-                  r->age_in_surv_rate_group_cond());
+                  r->has_surv_rate_group() ? r->age_in_surv_rate_group() : -1);
     return false;
   }
 };
@@ -404,7 +394,7 @@
 #endif // !PRODUCT
 
 double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) {
-  double young_start_time_sec = os::elapsedTime();
+  Ticks start_time = Ticks::now();
 
   finalize_incremental_building();
 
@@ -412,18 +402,16 @@
             "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
 
   size_t pending_cards = _policy->pending_cards_at_gc_start() + _g1h->hot_card_cache()->num_entries();
-  double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
-  double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0);
 
-  log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms",
-                            pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms);
+  log_trace(gc, ergo, cset)("Start choosing CSet. Pending cards: " SIZE_FORMAT " target pause time: %1.2fms",
+                            pending_cards, target_pause_time_ms);
 
   // The young list is laid with the survivor regions from the previous
   // pause are appended to the RHS of the young list, i.e.
   //   [Newly Young Regions ++ Survivors from last pause].
 
+  uint eden_region_length = _g1h->eden_regions_count();
   uint survivor_region_length = survivors->length();
-  uint eden_region_length = _g1h->eden_regions_count();
   init_region_lengths(eden_region_length, survivor_region_length);
 
   verify_young_cset_indices();
@@ -432,19 +420,23 @@
   survivors->convert_to_eden();
 
   _bytes_used_before = _inc_bytes_used_before;
-  time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0);
-
-  log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms",
-                            eden_region_length, survivor_region_length, _inc_predicted_elapsed_time_ms, target_pause_time_ms);
 
   // The number of recorded young regions is the incremental
   // collection set's current size
   set_recorded_rs_length(_inc_recorded_rs_length);
 
-  double young_end_time_sec = os::elapsedTime();
-  phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0);
+  double predicted_base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
+  double predicted_eden_time = _inc_predicted_non_copy_time_ms + _policy->predict_eden_copy_time_ms(eden_region_length);
+  double remaining_time_ms = MAX2(target_pause_time_ms - (predicted_base_time_ms + predicted_eden_time), 0.0);
 
-  return time_remaining_ms;
+  log_trace(gc, ergo, cset)("Added young regions to CSet. Eden: %u regions, Survivors: %u regions, "
+                            "predicted eden time: %1.2fms, predicted base time: %1.2fms, target pause time: %1.2fms, remaining time: %1.2fms",
+                            eden_region_length, survivor_region_length,
+                            predicted_eden_time, predicted_base_time_ms, target_pause_time_ms, remaining_time_ms);
+
+  phase_times()->record_young_cset_choice_time_ms((Ticks::now() - start_time).seconds() * 1000.0);
+
+  return remaining_time_ms;
 }
 
 static int compare_region_idx(const uint a, const uint b) {
--- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -174,6 +174,22 @@
   CSetBuildType _inc_build_state;
   size_t _inc_part_start;
 
+  // Information about eden regions in the incremental collection set.
+  struct IncCollectionSetRegionStat {
+    // The predicted non-copy time that was added to the total incremental value
+    // for the collection set.
+    double _non_copy_time_ms;
+    // The remembered set length that was added to the total incremental value
+    // for the collection set.
+    size_t _rs_length;
+
+#ifdef ASSERT
+    // Resets members to "uninitialized" values.
+    void reset() { _rs_length = ~(size_t)0; _non_copy_time_ms = -1.0; }
+#endif
+  };
+
+  IncCollectionSetRegionStat* _inc_collection_set_stats;
   // The associated information that is maintained while the incremental
   // collection set is being built with *young* regions. Used to populate
   // the recorded info for the evacuation pause.
@@ -195,25 +211,25 @@
   // the RSets grow. Instead of having to synchronize updates to that
   // field we accumulate them in this field and add it to
   // _inc_recorded_rs_length_diff at the start of a GC.
-  ssize_t _inc_recorded_rs_length_diff;
+  size_t _inc_recorded_rs_length_diff;
 
   // The predicted elapsed time it will take to collect the regions in
   // the CSet. This is updated by the thread that adds a new region to
   // the CSet. See the comment for _inc_recorded_rs_length about
   // MT-safety assumptions.
-  double _inc_predicted_elapsed_time_ms;
+  double _inc_predicted_non_copy_time_ms;
 
   // See the comment for _inc_recorded_rs_length_diff.
-  double _inc_predicted_elapsed_time_ms_diff;
+  double _inc_predicted_non_copy_time_ms_diff;
 
   void set_recorded_rs_length(size_t rs_length);
 
-  G1CollectorState* collector_state();
+  G1CollectorState* collector_state() const;
   G1GCPhaseTimes* phase_times();
 
   void verify_young_cset_indices() const NOT_DEBUG_RETURN;
 
-  double predict_region_elapsed_time_ms(HeapRegion* hr);
+  double predict_region_non_copy_time_ms(HeapRegion* hr) const;
 
   // Update the incremental collection set information when adding a region.
   void add_young_region_common(HeapRegion* hr);
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -2589,7 +2589,7 @@
   bool do_stealing = do_termination && !is_serial;
 
   G1Predictions const& predictor = _g1h->policy()->predictor();
-  double diff_prediction_ms = predictor.get_new_lower_zero_bound_prediction(&_marking_step_diff_ms);
+  double diff_prediction_ms = predictor.predict_zero_bounded(&_marking_step_diff_ms);
   _time_target_ms = time_target_ms - diff_prediction_ms;
 
   // set up the variables that are used in the work-based scheme to
--- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -113,8 +113,8 @@
     );
 }
 
-double G1AdaptiveIHOPControl::get_new_prediction(TruncatedSeq const* seq) const {
-  return _predictor->get_new_lower_zero_bound_prediction(seq);
+double G1AdaptiveIHOPControl::predict(TruncatedSeq const* seq) const {
+  return _predictor->predict_zero_bounded(seq);
 }
 
 bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const {
@@ -124,8 +124,8 @@
 
 size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() {
   if (have_enough_data_for_prediction()) {
-    double pred_marking_time = get_new_prediction(&_marking_times_s);
-    double pred_promotion_rate = get_new_prediction(&_allocation_rate_s);
+    double pred_marking_time = predict(&_marking_times_s);
+    double pred_promotion_rate = predict(&_allocation_rate_s);
     size_t pred_promotion_size = (size_t)(pred_marking_time * pred_promotion_rate);
 
     size_t predicted_needed_bytes_during_marking =
@@ -172,8 +172,8 @@
                       actual_target,
                       G1CollectedHeap::heap()->used(),
                       _last_unrestrained_young_size,
-                      get_new_prediction(&_allocation_rate_s),
-                      get_new_prediction(&_marking_times_s) * 1000.0,
+                      predict(&_allocation_rate_s),
+                      predict(&_marking_times_s) * 1000.0,
                       have_enough_data_for_prediction() ? "true" : "false");
 }
 
@@ -183,7 +183,7 @@
                                           actual_target_threshold(),
                                           G1CollectedHeap::heap()->used(),
                                           _last_unrestrained_young_size,
-                                          get_new_prediction(&_allocation_rate_s),
-                                          get_new_prediction(&_marking_times_s),
+                                          predict(&_allocation_rate_s),
+                                          predict(&_marking_times_s),
                                           have_enough_data_for_prediction());
 }
--- a/src/hotspot/share/gc/g1/g1IHOPControl.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1IHOPControl.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -124,7 +124,7 @@
   size_t _last_unrestrained_young_size;
 
   // Get a new prediction bounded below by zero from the given sequence.
-  double get_new_prediction(TruncatedSeq const* seq) const;
+  double predict(TruncatedSeq const* seq) const;
 
   bool have_enough_data_for_prediction() const;
 
--- a/src/hotspot/share/gc/g1/g1Policy.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -62,8 +62,8 @@
   _young_list_target_length(0),
   _young_list_fixed_length(0),
   _young_list_max_length(0),
-  _short_lived_surv_rate_group(new SurvRateGroup()),
-  _survivor_surv_rate_group(new SurvRateGroup()),
+  _eden_surv_rate_group(new G1SurvRateGroup()),
+  _survivor_surv_rate_group(new G1SurvRateGroup()),
   _reserve_factor((double) G1ReservePercent / 100.0),
   _reserve_regions(0),
   _young_gen_sizer(G1YoungGenSizer::create_gen_sizer()),
@@ -127,19 +127,16 @@
 }
 
 class G1YoungLengthPredictor {
-  const bool _during_cm;
   const double _base_time_ms;
   const double _base_free_regions;
   const double _target_pause_time_ms;
   const G1Policy* const _policy;
 
  public:
-  G1YoungLengthPredictor(bool during_cm,
-                         double base_time_ms,
+  G1YoungLengthPredictor(double base_time_ms,
                          double base_free_regions,
                          double target_pause_time_ms,
                          const G1Policy* policy) :
-    _during_cm(during_cm),
     _base_time_ms(base_time_ms),
     _base_free_regions(base_free_regions),
     _target_pause_time_ms(target_pause_time_ms),
@@ -151,11 +148,8 @@
       return false;
     }
 
-    const double accum_surv_rate = _policy->accum_yg_surv_rate_pred((int) young_length - 1);
-    const size_t bytes_to_copy =
-                 (size_t) (accum_surv_rate * (double) HeapRegion::GrainBytes);
-    const double copy_time_ms =
-      _policy->analytics()->predict_object_copy_time_ms(bytes_to_copy, _during_cm);
+    size_t bytes_to_copy = 0;
+    const double copy_time_ms = _policy->predict_eden_copy_time_ms(young_length, &bytes_to_copy);
     const double young_other_time_ms = _policy->analytics()->predict_young_other_time_ms(young_length);
     const double pause_time_ms = _base_time_ms + copy_time_ms + young_other_time_ms;
     if (pause_time_ms > _target_pause_time_ms) {
@@ -303,11 +297,10 @@
   return result;
 }
 
-uint
-G1Policy::calculate_young_list_target_length(size_t rs_length,
-                                                    uint base_min_length,
-                                                    uint desired_min_length,
-                                                    uint desired_max_length) const {
+uint G1Policy::calculate_young_list_target_length(size_t rs_length,
+                                                  uint base_min_length,
+                                                  uint desired_min_length,
+                                                  uint desired_max_length) const {
   assert(use_adaptive_young_list_length(), "pre-condition");
   assert(collector_state()->in_young_only_phase(), "only call this for young GCs");
 
@@ -327,11 +320,8 @@
   uint max_young_length = desired_max_length - base_min_length;
 
   const double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
-  const double survivor_regions_evac_time = predict_survivor_regions_evac_time();
   const size_t pending_cards = _analytics->predict_pending_cards();
-  const double base_time_ms =
-    predict_base_elapsed_time_ms(pending_cards, rs_length) +
-    survivor_regions_evac_time;
+  const double base_time_ms = predict_base_elapsed_time_ms(pending_cards, rs_length);
   const uint available_free_regions = _free_regions_at_end_of_collection;
   const uint base_free_regions =
     available_free_regions > _reserve_regions ? available_free_regions - _reserve_regions : 0;
@@ -339,8 +329,7 @@
   // Here, we will make sure that the shortest young length that
   // makes sense fits within the target pause time.
 
-  G1YoungLengthPredictor p(collector_state()->mark_or_rebuild_in_progress(),
-                           base_time_ms,
+  G1YoungLengthPredictor p(base_time_ms,
                            base_free_regions,
                            target_pause_time_ms,
                            this);
@@ -406,11 +395,10 @@
 double G1Policy::predict_survivor_regions_evac_time() const {
   double survivor_regions_evac_time = 0.0;
   const GrowableArray<HeapRegion*>* survivor_regions = _g1h->survivor()->regions();
-
   for (GrowableArrayIterator<HeapRegion*> it = survivor_regions->begin();
        it != survivor_regions->end();
        ++it) {
-    survivor_regions_evac_time += predict_region_elapsed_time_ms(*it, collector_state()->in_young_only_phase());
+    survivor_regions_evac_time += predict_region_total_time_ms(*it, collector_state()->in_young_only_phase());
   }
   return survivor_regions_evac_time;
 }
@@ -466,11 +454,10 @@
   collector_state()->set_mark_or_rebuild_in_progress(false);
   collector_state()->set_clearing_next_bitmap(false);
 
-  _short_lived_surv_rate_group->start_adding_regions();
+  _eden_surv_rate_group->start_adding_regions();
   // also call this on any additional surv rate groups
 
   _free_regions_at_end_of_collection = _g1h->num_free_regions();
-  // Reset survivors SurvRateGroup.
   _survivor_surv_rate_group->reset();
   update_young_list_max_and_target_length();
   update_rs_length_prediction();
@@ -553,7 +540,7 @@
   _collection_set->reset_bytes_used_before();
 
   // do that for any other surv rate groups
-  _short_lived_surv_rate_group->stop_adding_regions();
+  _eden_surv_rate_group->stop_adding_regions();
   _survivors_age_table.clear();
 
   assert(_g1h->collection_set()->verify_young_ages(), "region age verification failed");
@@ -711,7 +698,7 @@
     }
   }
 
-  _short_lived_surv_rate_group->start_adding_regions();
+  _eden_surv_rate_group->start_adding_regions();
 
   double merge_hcc_time_ms = average_time_ms(G1GCPhaseTimes::MergeHCC);
   if (update_stats) {
@@ -911,23 +898,14 @@
   phase_times()->print();
 }
 
-double G1Policy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const {
-  TruncatedSeq* seq = surv_rate_group->get_seq(age);
-  guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age);
-  return _predictor.get_new_unit_prediction(seq);
-}
-
-double G1Policy::accum_yg_surv_rate_pred(int age) const {
-  return _short_lived_surv_rate_group->accum_surv_rate_pred(age);
-}
-
 double G1Policy::predict_base_elapsed_time_ms(size_t pending_cards,
                                               size_t rs_length) const {
   size_t effective_scanned_cards = _analytics->predict_scan_card_num(rs_length, collector_state()->in_young_only_phase());
   return
     _analytics->predict_card_merge_time_ms(pending_cards + rs_length, collector_state()->in_young_only_phase()) +
     _analytics->predict_card_scan_time_ms(effective_scanned_cards, collector_state()->in_young_only_phase()) +
-    _analytics->predict_constant_other_time_ms();
+    _analytics->predict_constant_other_time_ms() +
+    predict_survivor_regions_evac_time();
 }
 
 double G1Policy::predict_base_elapsed_time_ms(size_t pending_cards) const {
@@ -940,25 +918,35 @@
   if (!hr->is_young()) {
     bytes_to_copy = hr->max_live_bytes();
   } else {
-    assert(hr->age_in_surv_rate_group() != -1, "invariant");
-    int age = hr->age_in_surv_rate_group();
-    double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group());
-    bytes_to_copy = (size_t) (hr->used() * yg_surv_rate);
+    bytes_to_copy = (size_t) (hr->used() * hr->surv_rate_prediction(_predictor));
   }
   return bytes_to_copy;
 }
 
-double G1Policy::predict_region_elapsed_time_ms(HeapRegion* hr,
-                                                bool for_young_gc) const {
+double G1Policy::predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy) const {
+  if (count == 0) {
+    return 0.0;
+  }
+  size_t const expected_bytes = _eden_surv_rate_group->accum_surv_rate_pred(count) * HeapRegion::GrainBytes;
+  if (bytes_to_copy != NULL) {
+    *bytes_to_copy = expected_bytes;
+  }
+  return _analytics->predict_object_copy_time_ms(expected_bytes, collector_state()->mark_or_rebuild_in_progress());
+}
+
+double G1Policy::predict_region_copy_time_ms(HeapRegion* hr) const {
+  size_t const bytes_to_copy = predict_bytes_to_copy(hr);
+  return _analytics->predict_object_copy_time_ms(bytes_to_copy, collector_state()->mark_or_rebuild_in_progress());
+}
+
+double G1Policy::predict_region_non_copy_time_ms(HeapRegion* hr,
+                                                 bool for_young_gc) const {
   size_t rs_length = hr->rem_set()->occupied();
   size_t scan_card_num = _analytics->predict_scan_card_num(rs_length, for_young_gc);
 
-  size_t bytes_to_copy = predict_bytes_to_copy(hr);
-
   double region_elapsed_time_ms =
     _analytics->predict_card_merge_time_ms(rs_length, collector_state()->in_young_only_phase()) +
-    _analytics->predict_card_scan_time_ms(scan_card_num, collector_state()->in_young_only_phase()) +
-    _analytics->predict_object_copy_time_ms(bytes_to_copy, collector_state()->mark_or_rebuild_in_progress());
+    _analytics->predict_card_scan_time_ms(scan_card_num, collector_state()->in_young_only_phase());
 
   // The prediction of the "other" time for this region is based
   // upon the region type and NOT the GC type.
@@ -970,6 +958,10 @@
   return region_elapsed_time_ms;
 }
 
+double G1Policy::predict_region_total_time_ms(HeapRegion* hr, bool for_young_gc) const {
+  return predict_region_non_copy_time_ms(hr, for_young_gc) + predict_region_copy_time_ms(hr);
+}
+
 bool G1Policy::should_allocate_mutator_region() const {
   uint young_list_length = _g1h->young_regions_count();
   uint young_list_target_length = _young_list_target_length;
@@ -1317,7 +1309,7 @@
       break;
     }
 
-    double predicted_time_ms = predict_region_elapsed_time_ms(hr, false);
+    double predicted_time_ms = predict_region_total_time_ms(hr, false);
     time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
     // Add regions to old set until we reach the minimum amount
     if (num_initial_regions < min_old_cset_length) {
@@ -1377,7 +1369,7 @@
   HeapRegion* r = candidates->at(candidate_idx);
   while (num_optional_regions < max_optional_regions) {
     assert(r != NULL, "Region must exist");
-    prediction_ms += predict_region_elapsed_time_ms(r, false);
+    prediction_ms += predict_region_total_time_ms(r, false);
 
     if (prediction_ms > time_remaining_ms) {
       log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.",
@@ -1396,10 +1388,7 @@
 }
 
 void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) {
-
-  // Add survivor regions to SurvRateGroup.
   note_start_adding_survivor_regions();
-  finished_recalculating_age_indexes(true /* is_survivors */);
 
   HeapRegion* last = NULL;
   for (GrowableArrayIterator<HeapRegion*> it = survivors->regions()->begin();
@@ -1421,6 +1410,4 @@
   // the next evacuation pause - we need it in order to re-tag
   // the survivor regions from this evacuation pause as 'young'
   // at the start of the next.
-
-  finished_recalculating_age_indexes(false /* is_survivors */);
 }
--- a/src/hotspot/share/gc/g1/g1Policy.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -82,10 +82,10 @@
   // locker is active. This should be >= _young_list_target_length;
   uint _young_list_max_length;
 
-  // SurvRateGroups below must be initialized after the predictor because they
-  // indirectly use it through this object passed to their constructor.
-  SurvRateGroup* _short_lived_surv_rate_group;
-  SurvRateGroup* _survivor_surv_rate_group;
+  // The survivor rate groups below must be initialized after the predictor because they
+  // indirectly use it through the "this" object passed to their constructor.
+  G1SurvRateGroup* _eden_surv_rate_group;
+  G1SurvRateGroup* _survivor_surv_rate_group;
 
   double _reserve_factor;
   // This will be set when the heap is expanded
@@ -128,7 +128,7 @@
 
   void set_region_eden(HeapRegion* hr) {
     hr->set_eden();
-    hr->install_surv_rate_group(_short_lived_surv_rate_group);
+    hr->install_surv_rate_group(_eden_surv_rate_group);
   }
 
   void set_region_survivor(HeapRegion* hr) {
@@ -141,17 +141,22 @@
   }
 
   double predict_base_elapsed_time_ms(size_t num_pending_cards) const;
-  double predict_base_elapsed_time_ms(size_t num_pending_cards,
-                                      size_t rs_length) const;
-  size_t predict_bytes_to_copy(HeapRegion* hr) const;
-  double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const;
 
-  double predict_survivor_regions_evac_time() const;
+private:
+  double predict_base_elapsed_time_ms(size_t num_pending_cards, size_t rs_length) const;
+
+  double predict_region_copy_time_ms(HeapRegion* hr) const;
+
+public:
+
+  double predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy = NULL) const;
+  double predict_region_non_copy_time_ms(HeapRegion* hr, bool for_young_gc) const;
+  double predict_region_total_time_ms(HeapRegion* hr, bool for_young_gc) const;
 
   void cset_regions_freed() {
     bool update = should_update_surv_rate_group_predictors();
 
-    _short_lived_surv_rate_group->all_surviving_words_recorded(predictor(), update);
+    _eden_surv_rate_group->all_surviving_words_recorded(predictor(), update);
     _survivor_surv_rate_group->all_surviving_words_recorded(predictor(), update);
   }
 
@@ -167,12 +172,6 @@
     return _mmu_tracker->max_gc_time() * 1000.0;
   }
 
-  double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const;
-
-  double predict_yg_surv_rate(int age) const;
-
-  double accum_yg_surv_rate_pred(int age) const;
-
 private:
   G1CollectionSet* _collection_set;
   double average_time_ms(G1GCPhaseTimes::GCParPhases phase) const;
@@ -236,6 +235,9 @@
   void update_rs_length_prediction();
   void update_rs_length_prediction(size_t prediction);
 
+  size_t predict_bytes_to_copy(HeapRegion* hr) const;
+  double predict_survivor_regions_evac_time() const;
+
   // Check whether a given young length (young_length) fits into the
   // given target pause time and whether the prediction for the amount
   // of objects to be copied for the given length will fit into the
@@ -375,14 +377,6 @@
   // the initial-mark work and start a marking cycle.
   void decide_on_conc_mark_initiation();
 
-  void finished_recalculating_age_indexes(bool is_survivors) {
-    if (is_survivors) {
-      _survivor_surv_rate_group->finished_recalculating_age_indexes();
-    } else {
-      _short_lived_surv_rate_group->finished_recalculating_age_indexes();
-    }
-  }
-
   size_t young_list_target_length() const { return _young_list_target_length; }
 
   bool should_allocate_mutator_region() const;
--- a/src/hotspot/share/gc/g1/g1Predictions.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1Predictions.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -54,16 +54,16 @@
   // Confidence factor.
   double sigma() const { return _sigma; }
 
-  double get_new_prediction(TruncatedSeq const* seq) const {
+  double predict(TruncatedSeq const* seq) const {
     return seq->davg() + _sigma * stddev_estimate(seq);
   }
 
-  double get_new_unit_prediction(TruncatedSeq const* seq) const {
-    return clamp(get_new_prediction(seq), 0.0, 1.0);
+  double predict_in_unit_interval(TruncatedSeq const* seq) const {
+    return clamp(predict(seq), 0.0, 1.0);
   }
 
-  double get_new_lower_zero_bound_prediction(TruncatedSeq const* seq) const {
-    return MAX2(get_new_prediction(seq), 0.0);
+  double predict_zero_bounded(TruncatedSeq const* seq) const {
+    return MAX2(predict(seq), 0.0);
   }
 };
 
--- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -172,7 +172,7 @@
                                     p2i(r->next_top_at_mark_start()),
                                     cm->liveness(r->hrm_index()) * HeapWordSize,
                                     r->next_marked_bytes(),
-                                    r->rem_set()->occupied_locked(),
+                                    r->rem_set()->occupied(),
                                     r->rem_set()->mem_size());
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1Predictions.hpp"
+#include "gc/g1/g1SurvRateGroup.hpp"
+#include "gc/g1/heapRegion.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.hpp"
+
+G1SurvRateGroup::G1SurvRateGroup() :
+  _stats_arrays_length(0),
+  _accum_surv_rate_pred(NULL),
+  _last_pred(0.0),
+  _surv_rate_predictors(NULL),
+  _num_added_regions(0) {
+  reset();
+  start_adding_regions();
+}
+
+void G1SurvRateGroup::reset() {
+  _last_pred = 0.0;
+  // the following will set up the arrays with length 1
+  _num_added_regions = 1;
+
+  // The call to stop_adding_regions() will use "new" to refill
+  // the _surv_rate_pred array, so we need to make sure to call
+  // "delete".
+  for (size_t i = 0; i < _stats_arrays_length; ++i) {
+    delete _surv_rate_predictors[i];
+  }
+  _stats_arrays_length = 0;
+
+  stop_adding_regions();
+
+  // Seed initial _surv_rate_pred and _accum_surv_rate_pred values
+  guarantee(_stats_arrays_length == 1, "invariant" );
+  guarantee(_surv_rate_predictors[0] != NULL, "invariant" );
+  const double initial_surv_rate = 0.4;
+  _surv_rate_predictors[0]->add(initial_surv_rate);
+  _last_pred = _accum_surv_rate_pred[0] = initial_surv_rate;
+
+  _num_added_regions = 0;
+}
+
+void G1SurvRateGroup::start_adding_regions() {
+  _num_added_regions = 0;
+}
+
+void G1SurvRateGroup::stop_adding_regions() {
+  if (_num_added_regions > _stats_arrays_length) {
+    _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(double, _accum_surv_rate_pred, _num_added_regions, mtGC);
+    _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_predictors, _num_added_regions, mtGC);
+
+    for (size_t i = _stats_arrays_length; i < _num_added_regions; ++i) {
+      _surv_rate_predictors[i] = new TruncatedSeq(10);
+    }
+
+    _stats_arrays_length = _num_added_regions;
+  }
+}
+
+void G1SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
+  guarantee(0 <= age_in_group && (size_t)age_in_group < _num_added_regions,
+            "age_in_group is %d not between 0 and " SIZE_FORMAT, age_in_group, _num_added_regions);
+
+  double surv_rate = (double)surv_words / HeapRegion::GrainWords;
+  _surv_rate_predictors[age_in_group]->add(surv_rate);
+}
+
+void G1SurvRateGroup::all_surviving_words_recorded(const G1Predictions& predictor, bool update_predictors) {
+  if (update_predictors) {
+    fill_in_last_surv_rates();
+  }
+  finalize_predictions(predictor);
+}
+
+void G1SurvRateGroup::fill_in_last_surv_rates() {
+  if (_num_added_regions > 0) { // conservative
+    double surv_rate = _surv_rate_predictors[_num_added_regions-1]->last();
+    for (size_t i = _num_added_regions; i < _stats_arrays_length; ++i) {
+      _surv_rate_predictors[i]->add(surv_rate);
+    }
+  }
+}
+
+void G1SurvRateGroup::finalize_predictions(const G1Predictions& predictor) {
+  double accum = 0.0;
+  double pred = 0.0;
+  for (size_t i = 0; i < _stats_arrays_length; ++i) {
+    pred = predictor.predict_in_unit_interval(_surv_rate_predictors[i]);
+    accum += pred;
+    _accum_surv_rate_pred[i] = accum;
+  }
+  _last_pred = pred;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2001, 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_GC_G1_G1SURVRATEGROUP_HPP
+#define SHARE_GC_G1_G1SURVRATEGROUP_HPP
+
+#include "gc/g1/g1Predictions.hpp"
+#include "utilities/numberSeq.hpp"
+
+// A survivor rate group tracks survival ratios of objects allocated in the
+// heap regions associated to a set of regions (a "space", i.e. eden or survivor)
+// on a time basis to predict future survival rates of regions of the same "age".
+//
+// Every time a new heap region associated with a survivor rate group is retired
+// (i.e. the time basis), it gets associated the next "age" entry in that group.
+//
+// During garbage collection G1 keeps track how much of total data is copied out
+// of a heap region (i.e. survives), to update the survivor rate predictor of that age.
+//
+// This information is used to predict, given a particular age of a heap region,
+// how much of its contents will likely survive to determine young generation sizes.
+//
+// The age index associated with a heap region is incremented from 0 (retired first)
+// to N (retired just before the GC).
+//
+// To avoid copying around data all the time when the total amount of regions in
+// a survivor rate group changes, this class organizes the arrays containing the
+// predictors in reverse chronological order as returned by age_in_group(). I.e.
+// index 0 contains the rate information for the region retired most recently.
+class G1SurvRateGroup : public CHeapObj<mtGC> {
+  size_t  _stats_arrays_length;
+  double* _accum_surv_rate_pred;
+  double  _last_pred;
+  TruncatedSeq** _surv_rate_predictors;
+
+  size_t _num_added_regions;   // The number of regions in this survivor rate group.
+
+  void fill_in_last_surv_rates();
+  void finalize_predictions(const G1Predictions& predictor);
+
+public:
+  static const int InvalidAgeIndex = -1;
+  static bool is_valid_age_index(int age) { return age >= 0; }
+
+  G1SurvRateGroup();
+  void reset();
+  void start_adding_regions();
+  void stop_adding_regions();
+  void record_surviving_words(int age_in_group, size_t surv_words);
+  void all_surviving_words_recorded(const G1Predictions& predictor, bool update_predictors);
+
+  double accum_surv_rate_pred(int age) const {
+    assert(_stats_arrays_length > 0, "invariant" );
+    assert(is_valid_age_index(age), "must be");
+    if ((size_t)age < _stats_arrays_length)
+      return _accum_surv_rate_pred[age];
+    else {
+      double diff = (double)(age - _stats_arrays_length + 1);
+      return _accum_surv_rate_pred[_stats_arrays_length - 1] + diff * _last_pred;
+    }
+  }
+
+  double surv_rate_pred(G1Predictions const& predictor, int age) const {
+    assert(is_valid_age_index(age), "must be");
+
+    age = MIN2(age, (int)_stats_arrays_length - 1);
+
+    return predictor.predict_in_unit_interval(_surv_rate_predictors[age]);
+  }
+
+  int next_age_index() {
+    return (int)++_num_added_regions;
+  }
+
+  int age_in_group(int age_index) const {
+    int result = (int)(_num_added_regions - age_index);
+    assert(is_valid_age_index(result), "invariant" );
+    return result;
+  }
+};
+
+#endif // SHARE_GC_G1_G1SURVRATEGROUP_HPP
--- a/src/hotspot/share/gc/g1/heapRegion.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegion.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -137,8 +137,6 @@
 
   _evacuation_failed = false;
   _gc_efficiency = 0.0;
-  _recorded_rs_length = 0;
-  _predicted_elapsed_time_ms = 0.0;
 }
 
 void HeapRegion::clear_cardtable() {
@@ -149,14 +147,12 @@
 void HeapRegion::calc_gc_efficiency() {
   // GC efficiency is the ratio of how much space would be
   // reclaimed over how long we predict it would take to reclaim it.
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  G1Policy* policy = g1h->policy();
+  G1Policy* policy = G1CollectedHeap::heap()->policy();
 
   // Retrieve a prediction of the elapsed time for this region for
   // a mixed gc because the region will only be evacuated during a
   // mixed gc.
-  double region_elapsed_time_ms =
-    policy->predict_region_elapsed_time_ms(this, false /* for_young_gc */);
+  double region_elapsed_time_ms = policy->predict_region_total_time_ms(this, false /* for_young_gc */);
   _gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
 }
 
@@ -256,8 +252,7 @@
   _prev_top_at_mark_start(NULL), _next_top_at_mark_start(NULL),
   _prev_marked_bytes(0), _next_marked_bytes(0),
   _young_index_in_cset(-1),
-  _surv_rate_group(NULL), _age_index(-1), _gc_efficiency(0.0),
-  _recorded_rs_length(0), _predicted_elapsed_time_ms(0),
+  _surv_rate_group(NULL), _age_index(G1SurvRateGroup::InvalidAgeIndex), _gc_efficiency(0.0),
   _node_index(G1NUMA::UnknownNodeIndex)
 {
   assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()),
--- a/src/hotspot/share/gc/g1/heapRegion.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegion.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -27,9 +27,9 @@
 
 #include "gc/g1/g1BlockOffsetTable.hpp"
 #include "gc/g1/g1HeapRegionTraceType.hpp"
+#include "gc/g1/g1SurvRateGroup.hpp"
 #include "gc/g1/heapRegionTracer.hpp"
 #include "gc/g1/heapRegionType.hpp"
-#include "gc/g1/survRateGroup.hpp"
 #include "gc/shared/ageTable.hpp"
 #include "gc/shared/spaceDecorator.hpp"
 #include "gc/shared/verifyOption.hpp"
@@ -38,6 +38,7 @@
 
 class G1CollectedHeap;
 class G1CMBitMap;
+class G1Predictions;
 class HeapRegionRemSet;
 class HeapRegion;
 class HeapRegionSetBase;
@@ -245,7 +246,7 @@
 
   // Data for young region survivor prediction.
   uint  _young_index_in_cset;
-  SurvRateGroup* _surv_rate_group;
+  G1SurvRateGroup* _surv_rate_group;
   int  _age_index;
 
   // Cached attributes used in the collection set policy information
@@ -253,14 +254,6 @@
   // The calculated GC efficiency of the region.
   double _gc_efficiency;
 
-  // The remembered set length that was added to the total value
-  // for the collection set.
-  size_t _recorded_rs_length;
-
-  // The predicted elapsed time that was added to total value
-  // for the collection set.
-  double _predicted_elapsed_time_ms;
-
   uint _node_index;
 
   void report_region_type_change(G1HeapRegionTraceType::Type to);
@@ -544,50 +537,17 @@
     _young_index_in_cset = index;
   }
 
-  int age_in_surv_rate_group() {
-    assert(_surv_rate_group != NULL, "pre-condition");
-    assert(_age_index > -1, "pre-condition");
-    return _surv_rate_group->age_in_group(_age_index);
-  }
+  int age_in_surv_rate_group() const;
+  bool has_valid_age_in_surv_rate() const;
 
-  void record_surv_words_in_group(size_t words_survived) {
-    assert(_surv_rate_group != NULL, "pre-condition");
-    assert(_age_index > -1, "pre-condition");
-    int age_in_group = age_in_surv_rate_group();
-    _surv_rate_group->record_surviving_words(age_in_group, words_survived);
-  }
+  bool has_surv_rate_group() const;
 
-  int age_in_surv_rate_group_cond() {
-    if (_surv_rate_group != NULL)
-      return age_in_surv_rate_group();
-    else
-      return -1;
-  }
+  double surv_rate_prediction(G1Predictions const& predictor) const;
 
-  SurvRateGroup* surv_rate_group() {
-    return _surv_rate_group;
-  }
+  void install_surv_rate_group(G1SurvRateGroup* surv_rate_group);
+  void uninstall_surv_rate_group();
 
-  void install_surv_rate_group(SurvRateGroup* surv_rate_group) {
-    assert(surv_rate_group != NULL, "pre-condition");
-    assert(_surv_rate_group == NULL, "pre-condition");
-    assert(is_young(), "pre-condition");
-
-    _surv_rate_group = surv_rate_group;
-    _age_index = surv_rate_group->next_age_index();
-  }
-
-  void uninstall_surv_rate_group() {
-    if (_surv_rate_group != NULL) {
-      assert(_age_index > -1, "pre-condition");
-      assert(is_young(), "pre-condition");
-
-      _surv_rate_group = NULL;
-      _age_index = -1;
-    } else {
-      assert(_age_index == -1, "pre-condition");
-    }
-  }
+  void record_surv_words_in_group(size_t words_survived);
 
   // Determine if an object has been allocated since the last
   // mark performed by the collector. This returns true iff the object
@@ -610,17 +570,6 @@
   template <bool is_gc_active, class Closure>
   inline HeapWord* oops_on_memregion_seq_iterate_careful(MemRegion mr, Closure* cl);
 
-  size_t recorded_rs_length() const        { return _recorded_rs_length; }
-  double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }
-
-  void set_recorded_rs_length(size_t rs_length) {
-    _recorded_rs_length = rs_length;
-  }
-
-  void set_predicted_elapsed_time_ms(double ms) {
-    _predicted_elapsed_time_ms = ms;
-  }
-
   // Routines for managing a list of code roots (attached to the
   // this region's RSet) that point into this heap region.
   void add_strong_code_root(nmethod* nm);
--- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -28,6 +28,7 @@
 #include "gc/g1/g1BlockOffsetTable.inline.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp"
+#include "gc/g1/g1Predictions.hpp"
 #include "gc/g1/heapRegion.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/atomic.hpp"
@@ -370,4 +371,51 @@
   }
 }
 
+inline int HeapRegion::age_in_surv_rate_group() const {
+  assert(has_surv_rate_group(), "pre-condition");
+  assert(has_valid_age_in_surv_rate(), "pre-condition");
+  return _surv_rate_group->age_in_group(_age_index);
+}
+
+inline bool HeapRegion::has_valid_age_in_surv_rate() const {
+  return G1SurvRateGroup::is_valid_age_index(_age_index);
+}
+
+inline bool HeapRegion::has_surv_rate_group() const {
+  return _surv_rate_group != NULL;
+}
+
+inline double HeapRegion::surv_rate_prediction(G1Predictions const& predictor) const {
+  assert(has_surv_rate_group(), "pre-condition");
+  return _surv_rate_group->surv_rate_pred(predictor, age_in_surv_rate_group());
+}
+
+inline void HeapRegion::install_surv_rate_group(G1SurvRateGroup* surv_rate_group) {
+  assert(surv_rate_group != NULL, "pre-condition");
+  assert(!has_surv_rate_group(), "pre-condition");
+  assert(is_young(), "pre-condition");
+
+  _surv_rate_group = surv_rate_group;
+  _age_index = surv_rate_group->next_age_index();
+}
+
+inline void HeapRegion::uninstall_surv_rate_group() {
+  if (has_surv_rate_group()) {
+    assert(has_valid_age_in_surv_rate(), "pre-condition");
+    assert(is_young(), "pre-condition");
+
+    _surv_rate_group = NULL;
+    _age_index = G1SurvRateGroup::InvalidAgeIndex;
+  } else {
+    assert(!has_valid_age_in_surv_rate(), "pre-condition");
+  }
+}
+
+inline void HeapRegion::record_surv_words_in_group(size_t words_survived) {
+  assert(has_surv_rate_group(), "pre-condition");
+  assert(has_valid_age_in_surv_rate(), "pre-condition");
+  int age_in_group = age_in_surv_rate_group();
+  _surv_rate_group->record_surviving_words(age_in_group, words_survived);
+}
+
 #endif // SHARE_GC_G1_HEAPREGION_INLINE_HPP
--- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -28,7 +28,7 @@
 #include "gc/g1/g1ConcurrentRefine.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
 #include "gc/g1/heapRegionRemSet.inline.hpp"
-#include "gc/shared/space.inline.hpp"
+#include "gc/g1/sparsePRT.inline.hpp"
 #include "memory/allocation.hpp"
 #include "memory/padded.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -68,6 +68,7 @@
 OtherRegionsTable::OtherRegionsTable(Mutex* m) :
   _g1h(G1CollectedHeap::heap()),
   _m(m),
+  _num_occupied(0),
   _coarse_map(G1CollectedHeap::heap()->max_regions(), mtGC),
   _n_coarse_entries(0),
   _fine_grain_regions(NULL),
@@ -183,6 +184,7 @@
     return;
   }
 
+  size_t num_added_by_coarsening = 0;
   // Otherwise find a per-region table to add it to.
   size_t ind = from_hrm_ind & _mod_max_fine_entries_mask;
   PerRegionTable* prt = find_region_table(ind, from_hr);
@@ -194,13 +196,17 @@
 
       CardIdx_t card_index = card_within_region(from, from_hr);
 
-      if (_sparse_table.add_card(from_hrm_ind, card_index)) {
+      SparsePRT::AddCardResult result = _sparse_table.add_card(from_hrm_ind, card_index);
+      if (result != SparsePRT::overflow) {
+        if (result == SparsePRT::added) {
+          Atomic::inc(&_num_occupied, memory_order_relaxed);
+        }
         assert(contains_reference_locked(from), "We just added " PTR_FORMAT " to the Sparse table", p2i(from));
         return;
       }
 
       if (_n_fine_entries == _max_fine_entries) {
-        prt = delete_region_table();
+        prt = delete_region_table(num_added_by_coarsening);
         // There is no need to clear the links to the 'all' list here:
         // prt will be reused immediately, i.e. remain in the 'all' list.
         prt->init(from_hr, false /* clear_links_to_all_list */);
@@ -222,7 +228,8 @@
       Atomic::release_store(&_fine_grain_regions[ind], prt);
       _n_fine_entries++;
 
-      // Transfer from sparse to fine-grain.
+      // Transfer from sparse to fine-grain. The cards from the sparse table
+      // were already added to the total in _num_occupied.
       SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrm_ind);
       assert(sprt_entry != NULL, "There should have been an entry");
       for (int i = 0; i < sprt_entry->num_valid_cards(); i++) {
@@ -240,7 +247,11 @@
   // OtherRegionsTable for why this is OK.
   assert(prt != NULL, "Inv");
 
-  prt->add_reference(from);
+  bool added = prt->add_reference(from);
+  if (prt->add_reference(from)) {
+    num_added_by_coarsening++;
+  }
+  Atomic::add(&_num_occupied, num_added_by_coarsening, memory_order_relaxed);
   assert(contains_reference(from), "We just added " PTR_FORMAT " to the PRT (%d)", p2i(from), prt->contains_reference(from));
 }
 
@@ -257,7 +268,7 @@
 
 jint OtherRegionsTable::_n_coarsenings = 0;
 
-PerRegionTable* OtherRegionsTable::delete_region_table() {
+PerRegionTable* OtherRegionsTable::delete_region_table(size_t& added_by_deleted) {
   assert(_m->owned_by_self(), "Precondition");
   assert(_n_fine_entries == _max_fine_entries, "Precondition");
   PerRegionTable* max = NULL;
@@ -307,6 +318,7 @@
     _n_coarse_entries++;
   }
 
+  added_by_deleted = HeapRegion::CardsPerRegion - max_occ;
   // Unsplice.
   *max_prev = max->collision_list_next();
   Atomic::inc(&_n_coarsenings);
@@ -315,48 +327,15 @@
 }
 
 bool OtherRegionsTable::occupancy_less_or_equal_than(size_t limit) const {
-  if (limit <= (size_t)G1RSetSparseRegionEntries) {
-    return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= limit;
-  } else {
-    // Current uses of this method may only use values less than G1RSetSparseRegionEntries
-    // for the limit. The solution, comparing against occupied() would be too slow
-    // at this time.
-    Unimplemented();
-    return false;
-  }
+  return occupied() <= limit;
 }
 
 bool OtherRegionsTable::is_empty() const {
-  return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
+  return occupied() == 0;
 }
 
 size_t OtherRegionsTable::occupied() const {
-  size_t sum = occ_fine();
-  sum += occ_sparse();
-  sum += occ_coarse();
-  return sum;
-}
-
-size_t OtherRegionsTable::occ_fine() const {
-  size_t sum = 0;
-
-  size_t num = 0;
-  PerRegionTable * cur = _first_all_fine_prts;
-  while (cur != NULL) {
-    sum += cur->occupied();
-    cur = cur->next();
-    num++;
-  }
-  guarantee(num == _n_fine_entries, "just checking");
-  return sum;
-}
-
-size_t OtherRegionsTable::occ_coarse() const {
-  return (_n_coarse_entries * HeapRegion::CardsPerRegion);
-}
-
-size_t OtherRegionsTable::occ_sparse() const {
-  return _sparse_table.occupied();
+  return _num_occupied;
 }
 
 size_t OtherRegionsTable::mem_size() const {
@@ -399,6 +378,8 @@
   }
   _n_fine_entries = 0;
   _n_coarse_entries = 0;
+
+  _num_occupied = 0;
 }
 
 bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
@@ -465,7 +446,7 @@
   clear_fcc();
   _other_regions.clear();
   set_state_empty();
-  assert(occupied_locked() == 0, "Should be clear.");
+  assert(occupied() == 0, "Should be clear.");
 }
 
 // Code roots support
--- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -71,6 +71,8 @@
   G1CollectedHeap* _g1h;
   Mutex*           _m;
 
+  size_t volatile _num_occupied;
+
   // These are protected by "_m".
   CHeapBitMap _coarse_map;
   size_t      _n_coarse_entries;
@@ -107,7 +109,7 @@
   // Find, delete, and return a candidate PerRegionTable, if any exists,
   // adding the deleted region to the coarse bitmap.  Requires the caller
   // to hold _m, and the fine-grain table to be full.
-  PerRegionTable* delete_region_table();
+  PerRegionTable* delete_region_table(size_t& added_by_deleted);
 
   // link/add the given fine grain remembered set into the "all" list
   void link_to_all(PerRegionTable * prt);
@@ -116,10 +118,6 @@
 
   bool contains_reference_locked(OopOrNarrowOopStar from) const;
 
-  size_t occ_fine() const;
-  size_t occ_coarse() const;
-  size_t occ_sparse() const;
-
 public:
   // Create a new remembered set. The given mutex is used to ensure consistency.
   OtherRegionsTable(Mutex* m);
@@ -194,16 +192,14 @@
   HeapRegion* hr() const { return Atomic::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 bool add_reference(OopOrNarrowOopStar from);
 
-  inline void add_card(CardIdx_t from_card_index);
+  inline bool 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.)
@@ -325,10 +321,6 @@
   inline void iterate_prts(Closure& cl);
 
   size_t occupied() {
-    MutexLocker x(&_m, Mutex::_no_safepoint_check_flag);
-    return occupied_locked();
-  }
-  size_t occupied_locked() {
     return _other_regions.occupied();
   }
 
--- a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -36,13 +36,15 @@
   _other_regions.iterate(cl);
 }
 
-inline void PerRegionTable::add_card(CardIdx_t from_card_index) {
+inline bool PerRegionTable::add_card(CardIdx_t from_card_index) {
   if (_bm.par_set_bit(from_card_index)) {
-    Atomic::inc(&_occupied);
+    Atomic::inc(&_occupied, memory_order_relaxed);
+    return true;
   }
+  return false;
 }
 
-inline void PerRegionTable::add_reference(OopOrNarrowOopStar from) {
+inline bool PerRegionTable::add_reference(OopOrNarrowOopStar from) {
   // Must make this robust in case "from" is not in "_hr", because of
   // concurrency.
 
@@ -52,8 +54,9 @@
   // 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(from_card);
+    return add_card(from_card);
   }
+  return false;
 }
 
 inline void PerRegionTable::init(HeapRegion* hr, bool clear_links_to_all_list) {
--- a/src/hotspot/share/gc/g1/sparsePRT.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/sparsePRT.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -56,19 +56,19 @@
   return false;
 }
 
-SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
+SparsePRT::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
   for (int i = 0; i < num_valid_cards(); i++) {
     if (card(i) == card_index) {
-      return found;
+      return SparsePRT::found;
     }
   }
   if (num_valid_cards() < cards_num() - 1) {
     _cards[_next_null] = (card_elem_t)card_index;
     _next_null++;
-    return added;
+    return SparsePRT::added;
    }
   // Otherwise, we're full.
-  return overflow;
+  return SparsePRT::overflow;
 }
 
 void SparsePRTEntry::copy_cards(card_elem_t* cards) const {
@@ -91,7 +91,6 @@
   _capacity(capacity),
   _capacity_mask(capacity-1),
   _occupied_entries(0),
-  _occupied_cards(0),
   _entries(NULL),
   _buckets(NEW_C_HEAP_ARRAY(int, capacity, mtGC)),
   _free_region(0),
@@ -109,7 +108,6 @@
 
 void RSHashTable::clear() {
   _occupied_entries = 0;
-  _occupied_cards = 0;
   guarantee(_entries != NULL, "INV");
   guarantee(_buckets != NULL, "INV");
 
@@ -123,14 +121,13 @@
   _free_region = 0;
 }
 
-bool RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) {
+SparsePRT::AddCardResult RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) {
   SparsePRTEntry* e = entry_for_region_ind_create(region_ind);
   assert(e != NULL && e->r_ind() == region_ind,
          "Postcondition of call above.");
-  SparsePRTEntry::AddCardResult res = e->add_card(card_index);
-  if (res == SparsePRTEntry::added) _occupied_cards++;
+  SparsePRT::AddCardResult res = e->add_card(card_index);
   assert(e->num_valid_cards() > 0, "Postcondition");
-  return res != SparsePRTEntry::overflow;
+  return res;
 }
 
 SparsePRTEntry* RSHashTable::get_entry(RegionIdx_t region_ind) const {
@@ -163,7 +160,6 @@
   if (cur_ind == NullEntry) return false;
   // Otherwise, splice out "cur".
   *prev_loc = cur->next_index();
-  _occupied_cards -= cur->num_valid_cards();
   free_entry(cur_ind);
   _occupied_entries--;
   return true;
@@ -209,7 +205,6 @@
   assert(e->num_valid_cards() > 0, "Precondition.");
   SparsePRTEntry* e2 = entry_for_region_ind_create(e->r_ind());
   e->copy_cards(e2);
-  _occupied_cards += e2->num_valid_cards();
   assert(e2->num_valid_cards() > 0, "Postcondition.");
 }
 
@@ -309,7 +304,7 @@
   return sizeof(SparsePRT) + _table->mem_size();
 }
 
-bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
+SparsePRT::AddCardResult SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
   if (_table->should_expand()) {
     expand();
   }
--- a/src/hotspot/share/gc/g1/sparsePRT.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/gc/g1/sparsePRT.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -33,9 +33,56 @@
 #include "utilities/align.hpp"
 #include "utilities/globalDefinitions.hpp"
 
+class RSHashTable;
+class SparsePRTEntry;
+class SparsePRTIter;
+
 // Sparse remembered set for a heap region (the "owning" region).  Maps
 // indices of other regions to short sequences of cards in the other region
 // that might contain pointers into the owner region.
+// Concurrent access to a SparsePRT must be serialized by some external mutex.
+class SparsePRT {
+  friend class SparsePRTIter;
+  friend class SparsePRTBucketIter;
+
+  RSHashTable* _table;
+
+  static const size_t InitialCapacity = 8;
+
+  void expand();
+
+public:
+  SparsePRT();
+  ~SparsePRT();
+
+  size_t mem_size() const;
+
+  enum AddCardResult {
+    overflow, // The table is full, could not add the card to the table.
+    found,    // The card is already in the PRT.
+    added     // The card has been added.
+  };
+
+  // Attempts to ensure that the given card_index in the given region is in
+  // the sparse table.  If successful (because the card was already
+  // present, or because it was successfully added) returns "true".
+  // Otherwise, returns "false" to indicate that the addition would
+  // overflow the entry for the region.  The caller must transfer these
+  // entries to a larger-capacity representation.
+  AddCardResult add_card(RegionIdx_t region_id, CardIdx_t card_index);
+
+  // Return the pointer to the entry associated with the given region.
+  SparsePRTEntry* get_entry(RegionIdx_t region_ind);
+
+  // If there is an entry for "region_ind", removes it and return "true";
+  // otherwise returns "false."
+  bool delete_entry(RegionIdx_t region_ind);
+
+  // Clear the table, and reinitialize to initial capacity.
+  void clear();
+
+  bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
+};
 
 class SparsePRTEntry: public CHeapObj<mtGC> {
 public:
@@ -84,15 +131,7 @@
   // Returns the number of non-NULL card entries.
   inline int num_valid_cards() const { return _next_null; }
 
-  // Requires that the entry not contain the given card index.  If there is
-  // space available, add the given card index to the entry and return
-  // "true"; otherwise, return "false" to indicate that the entry is full.
-  enum AddCardResult {
-    overflow,
-    found,
-    added
-  };
-  inline AddCardResult add_card(CardIdx_t card_index);
+  inline SparsePRT::AddCardResult add_card(CardIdx_t card_index);
 
   // Copy the current entry's cards into the "_card" array of "e."
   inline void copy_cards(SparsePRTEntry* e) const;
@@ -153,7 +192,7 @@
   // Otherwise, returns "false" to indicate that the addition would
   // overflow the entry for the region.  The caller must transfer these
   // entries to a larger-capacity representation.
-  bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
+  SparsePRT::AddCardResult add_card(RegionIdx_t region_id, CardIdx_t card_index);
 
   bool delete_entry(RegionIdx_t region_id);
 
@@ -168,7 +207,6 @@
   size_t capacity() const      { return _capacity; }
   size_t capacity_mask() const { return _capacity_mask;  }
   size_t occupied_entries() const { return _occupied_entries; }
-  size_t occupied_cards() const   { return _occupied_cards; }
   size_t mem_size() const;
   // The number of SparsePRTEntry instances available.
   size_t num_entries() const { return _num_entries; }
@@ -228,50 +266,6 @@
   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;
-
-  static const size_t InitialCapacity = 8;
-
-  void expand();
-
-public:
-  SparsePRT();
-  ~SparsePRT();
-
-  size_t occupied() const { return _table->occupied_cards(); }
-  size_t mem_size() const;
-
-  // Attempts to ensure that the given card_index in the given region is in
-  // the sparse table.  If successful (because the card was already
-  // present, or because it was successfully added) returns "true".
-  // Otherwise, returns "false" to indicate that the addition would
-  // overflow the entry for the region.  The caller must transfer these
-  // entries to a larger-capacity representation.
-  bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
-
-  // Return the pointer to the entry associated with the given region.
-  SparsePRTEntry* get_entry(RegionIdx_t region_ind);
-
-  // If there is an entry for "region_ind", removes it and return "true";
-  // otherwise returns "false."
-  bool delete_entry(RegionIdx_t region_ind);
-
-  // Clear the table, and reinitialize to initial capacity.
-  void clear();
-
-  bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
-    return _table->contains_card(region_id, card_index);
-  }
-};
-
 class SparsePRTIter: public RSHashTableIter {
 public:
   SparsePRTIter(const SparsePRT* sprt) :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/sparsePRT.inline.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_GC_G1_SPARSEPRT_INLINE_HPP
+#define SHARE_GC_G1_SPARSEPRT_INLINE_HPP
+
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/sparsePRT.hpp"
+
+inline bool SparsePRT::contains_card(RegionIdx_t region_id, CardIdx_t card_index) const {
+  return _table->contains_card(region_id, card_index);
+}
+
+
+#endif // SHARE_GC_G1_SPARSEPRT_INLINE_HPP
--- a/src/hotspot/share/gc/g1/survRateGroup.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1Predictions.hpp"
-#include "gc/g1/heapRegion.hpp"
-#include "gc/g1/survRateGroup.hpp"
-#include "logging/log.hpp"
-#include "memory/allocation.hpp"
-
-SurvRateGroup::SurvRateGroup() :
-  _stats_arrays_length(0),
-  _accum_surv_rate_pred(NULL),
-  _last_pred(0.0),
-  _surv_rate_pred(NULL),
-  _all_regions_allocated(0),
-  _region_num(0),
-  _setup_seq_num(0)
-{
-  reset();
-  start_adding_regions();
-}
-
-void SurvRateGroup::reset() {
-  _all_regions_allocated = 0;
-  _setup_seq_num         = 0;
-  _last_pred             = 0.0;
-  // the following will set up the arrays with length 1
-  _region_num            = 1;
-
-  // The call to stop_adding_regions() will use "new" to refill
-  // the _surv_rate_pred array, so we need to make sure to call
-  // "delete".
-  for (size_t i = 0; i < _stats_arrays_length; ++i) {
-    delete _surv_rate_pred[i];
-  }
-  _stats_arrays_length = 0;
-
-  stop_adding_regions();
-
-  // Seed initial _surv_rate_pred and _accum_surv_rate_pred values
-  guarantee( _stats_arrays_length == 1, "invariant" );
-  guarantee( _surv_rate_pred[0] != NULL, "invariant" );
-  const double initial_surv_rate = 0.4;
-  _surv_rate_pred[0]->add(initial_surv_rate);
-  _last_pred = _accum_surv_rate_pred[0] = initial_surv_rate;
-
-  _region_num = 0;
-}
-
-void SurvRateGroup::start_adding_regions() {
-  _setup_seq_num   = _stats_arrays_length;
-  _region_num      = 0;
-}
-
-void SurvRateGroup::stop_adding_regions() {
-  if (_region_num > _stats_arrays_length) {
-    _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(double, _accum_surv_rate_pred, _region_num, mtGC);
-    _surv_rate_pred = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_pred, _region_num, mtGC);
-
-    for (size_t i = _stats_arrays_length; i < _region_num; ++i) {
-      _surv_rate_pred[i] = new TruncatedSeq(10);
-    }
-
-    _stats_arrays_length = _region_num;
-  }
-}
-
-void SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
-  guarantee( 0 <= age_in_group && (size_t) age_in_group < _region_num,
-             "pre-condition" );
-
-  double surv_rate = (double) surv_words / (double) HeapRegion::GrainWords;
-  _surv_rate_pred[age_in_group]->add(surv_rate);
-}
-
-void SurvRateGroup::all_surviving_words_recorded(const G1Predictions& predictor, bool update_predictors) {
-  if (update_predictors) {
-    fill_in_last_surv_rates();
-  }
-  finalize_predictions(predictor);
-}
-
-void SurvRateGroup::fill_in_last_surv_rates() {
-  if (_region_num > 0) { // conservative
-    double surv_rate = _surv_rate_pred[_region_num-1]->last();
-    for (size_t i = _region_num; i < _stats_arrays_length; ++i) {
-      _surv_rate_pred[i]->add(surv_rate);
-    }
-  }
-}
-
-void SurvRateGroup::finalize_predictions(const G1Predictions& predictor) {
-  double accum = 0.0;
-  double pred = 0.0;
-  for (size_t i = 0; i < _stats_arrays_length; ++i) {
-    pred = predictor.get_new_unit_prediction(_surv_rate_pred[i]);
-    accum += pred;
-    _accum_surv_rate_pred[i] = accum;
-  }
-  _last_pred = pred;
-}
--- a/src/hotspot/share/gc/g1/survRateGroup.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2001, 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_GC_G1_SURVRATEGROUP_HPP
-#define SHARE_GC_G1_SURVRATEGROUP_HPP
-
-#include "utilities/numberSeq.hpp"
-
-class G1Predictions;
-
-class SurvRateGroup : public CHeapObj<mtGC> {
-private:
-  size_t  _stats_arrays_length;
-  double* _accum_surv_rate_pred;
-  double  _last_pred;
-  TruncatedSeq** _surv_rate_pred;
-
-  int _all_regions_allocated;
-  size_t _region_num;
-  size_t _setup_seq_num;
-
-  void fill_in_last_surv_rates();
-  void finalize_predictions(const G1Predictions& predictor);
-public:
-  SurvRateGroup();
-  void reset();
-  void start_adding_regions();
-  void stop_adding_regions();
-  void record_surviving_words(int age_in_group, size_t surv_words);
-  void all_surviving_words_recorded(const G1Predictions& predictor, bool update_predictors);
-
-  size_t region_num() const { return _region_num; }
-
-  double accum_surv_rate_pred(int age) const {
-    assert(age >= 0, "must be");
-    if ((size_t)age < _stats_arrays_length)
-      return _accum_surv_rate_pred[age];
-    else {
-      double diff = (double) (age - _stats_arrays_length + 1);
-      return _accum_surv_rate_pred[_stats_arrays_length-1] + diff * _last_pred;
-    }
-  }
-
-  TruncatedSeq* get_seq(size_t age) const {
-    if (age >= _setup_seq_num) {
-      guarantee( _setup_seq_num > 0, "invariant" );
-      age = _setup_seq_num-1;
-    }
-    TruncatedSeq* seq = _surv_rate_pred[age];
-    guarantee( seq != NULL, "invariant" );
-    return seq;
-  }
-
-  int next_age_index() {
-    ++_region_num;
-    return (int) ++_all_regions_allocated;
-  }
-
-  int age_in_group(int age_index) const {
-    int ret = (int) (_all_regions_allocated - age_index);
-    assert( ret >= 0, "invariant" );
-    return ret;
-  }
-  void finished_recalculating_age_indexes() {
-    _all_regions_allocated = 0;
-  }
-
-};
-
-#endif // SHARE_GC_G1_SURVRATEGROUP_HPP
--- a/src/hotspot/share/oops/instanceKlass.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1980,7 +1980,7 @@
         // we're single threaded or at a safepoint - no locking needed
         get_jmethod_id_length_value(jmeths, idnum, &length, &id);
       } else {
-        MutexLocker ml(JmethodIdCreation_lock);
+        MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
         get_jmethod_id_length_value(jmeths, idnum, &length, &id);
       }
     }
@@ -2030,7 +2030,7 @@
       id = get_jmethod_id_fetch_or_update(idnum, new_id, new_jmeths,
                                           &to_dealloc_id, &to_dealloc_jmeths);
     } else {
-      MutexLocker ml(JmethodIdCreation_lock);
+      MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
       id = get_jmethod_id_fetch_or_update(idnum, new_id, new_jmeths,
                                           &to_dealloc_id, &to_dealloc_jmeths);
     }
--- a/src/hotspot/share/prims/jvmtiExport.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/prims/jvmtiExport.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1349,20 +1349,27 @@
   if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
     return;
   }
-  Thread *thread = Thread::current();
+
+  // postings to the service thread so that it can perform them in a safe
+  // context and in-order.
+  MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
+  ResourceMark rm;
+  // JvmtiDeferredEvent copies the string.
+  JvmtiDeferredEvent event = JvmtiDeferredEvent::class_unload_event(klass->name()->as_C_string());
+  JvmtiDeferredEventQueue::enqueue(event);
+}
+
+
+void JvmtiExport::post_class_unload_internal(const char* name) {
+  if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
+    return;
+  }
+  assert(Thread::current()->is_service_thread(), "must be called from ServiceThread");
+  JavaThread *thread = JavaThread::current();
   HandleMark hm(thread);
 
   EVT_TRIG_TRACE(EXT_EVENT_CLASS_UNLOAD, ("[?] Trg Class Unload triggered" ));
   if (JvmtiEventController::is_enabled((jvmtiEvent)EXT_EVENT_CLASS_UNLOAD)) {
-    assert(thread->is_VM_thread(), "wrong thread");
-
-    // get JavaThread for whom we are proxy
-    Thread *calling_thread = ((VMThread *)thread)->vm_operation()->calling_thread();
-    if (!calling_thread->is_Java_thread()) {
-      // cannot post an event to a non-JavaThread
-      return;
-    }
-    JavaThread *real_thread = (JavaThread *)calling_thread;
 
     JvmtiEnvIterator it;
     for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
@@ -1370,33 +1377,14 @@
         continue;
       }
       if (env->is_enabled((jvmtiEvent)EXT_EVENT_CLASS_UNLOAD)) {
-        EVT_TRACE(EXT_EVENT_CLASS_UNLOAD, ("[?] Evt Class Unload sent %s",
-                  klass==NULL? "NULL" : klass->external_name() ));
-
-        // do everything manually, since this is a proxy - needs special care
-        JNIEnv* jni_env = real_thread->jni_environment();
-        jthread jt = (jthread)JNIHandles::make_local(real_thread, real_thread->threadObj());
-        jclass jk = (jclass)JNIHandles::make_local(real_thread, klass->java_mirror());
-
-        // Before we call the JVMTI agent, we have to set the state in the
-        // thread for which we are proxying.
-        JavaThreadState prev_state = real_thread->thread_state();
-        assert(((Thread *)real_thread)->is_ConcurrentGC_thread() ||
-               (real_thread->is_Java_thread() && prev_state == _thread_blocked),
-               "should be ConcurrentGCThread or JavaThread at safepoint");
-        real_thread->set_thread_state(_thread_in_native);
-
+        EVT_TRACE(EXT_EVENT_CLASS_UNLOAD, ("[?] Evt Class Unload sent %s", name));
+
+        JvmtiEventMark jem(thread);
+        JvmtiJavaThreadEventTransition jet(thread);
         jvmtiExtensionEvent callback = env->ext_callbacks()->ClassUnload;
         if (callback != NULL) {
-          (*callback)(env->jvmti_external(), jni_env, jt, jk);
+          (*callback)(env->jvmti_external(), jem.jni_env(), name);
         }
-
-        assert(real_thread->thread_state() == _thread_in_native,
-               "JavaThread should be in native");
-        real_thread->set_thread_state(prev_state);
-
-        JNIHandles::destroy_local(jk);
-        JNIHandles::destroy_local(jt);
       }
     }
   }
@@ -2155,7 +2143,7 @@
     int stackframe = 0;
     for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
       // sd->method() can be NULL for stubs but not for nmethods. To be completely robust, include an assert that we should never see a null sd->method()
-      assert(sd->method() != NULL, "sd->method() cannot be null.");
+      guarantee(sd->method() != NULL, "sd->method() cannot be null.");
       record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id();
       record->pcinfo[scope].bcis[stackframe] = sd->bci();
       stackframe++;
@@ -2166,6 +2154,7 @@
 }
 
 void JvmtiExport::post_compiled_method_load(nmethod *nm) {
+  guarantee(!nm->is_unloading(), "nmethod isn't unloaded or unloading");
   if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
     return;
   }
--- a/src/hotspot/share/prims/jvmtiExport.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/prims/jvmtiExport.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -160,6 +160,7 @@
   // internal implementation.  Also called from JvmtiDeferredEvent::post()
   static void post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) NOT_JVMTI_RETURN;
 
+  static void post_class_unload_internal(const char *name) NOT_JVMTI_RETURN;
  private:
 
   // GenerateEvents support to allow posting of CompiledMethodLoad and
--- a/src/hotspot/share/prims/jvmtiExtensions.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/prims/jvmtiExtensions.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -70,9 +70,8 @@
   // register our extension event
 
   static jvmtiParamInfo event_params[] = {
-    { (char*)"JNI Environment", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, JNI_FALSE },
-    { (char*)"Thread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE },
-    { (char*)"Class", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, JNI_FALSE }
+    { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
+    { (char*)"Class", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, JNI_FALSE }
   };
   static jvmtiExtensionEventInfo ext_event = {
     EXT_EVENT_CLASS_UNLOAD,
--- a/src/hotspot/share/prims/jvmtiImpl.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/prims/jvmtiImpl.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -908,9 +908,6 @@
     nmethod* nm) {
   JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
   event._event_data.compiled_method_load = nm;
-  // Keep the nmethod alive until the ServiceThread can process
-  // this deferred event.
-  nmethodLocker::lock_nmethod(nm);
   return event;
 }
 
@@ -942,15 +939,23 @@
   return event;
 }
 
+JvmtiDeferredEvent JvmtiDeferredEvent::class_unload_event(const char* name) {
+  JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_CLASS_UNLOAD);
+  // Need to make a copy of the name since we don't know how long
+  // the event poster will keep it around after we enqueue the
+  // deferred event and return. strdup() failure is handled in
+  // the post() routine below.
+  event._event_data.class_unload.name = os::strdup(name);
+  return event;
+}
+
 void JvmtiDeferredEvent::post() {
-  assert(ServiceThread::is_service_thread(Thread::current()),
+  assert(Thread::current()->is_service_thread(),
          "Service thread must post enqueued events");
   switch(_type) {
     case TYPE_COMPILED_METHOD_LOAD: {
       nmethod* nm = _event_data.compiled_method_load;
       JvmtiExport::post_compiled_method_load(nm);
-      // done with the deferred event so unlock the nmethod
-      nmethodLocker::unlock_nmethod(nm);
       break;
     }
     case TYPE_COMPILED_METHOD_UNLOAD: {
@@ -975,11 +980,37 @@
       }
       break;
     }
+    case TYPE_CLASS_UNLOAD: {
+      JvmtiExport::post_class_unload_internal(
+        // if strdup failed give the event a default name
+        (_event_data.class_unload.name == NULL)
+          ? "unknown_class" : _event_data.class_unload.name);
+      if (_event_data.class_unload.name != NULL) {
+        // release our copy
+        os::free((void *)_event_data.class_unload.name);
+      }
+      break;
+    }
     default:
       ShouldNotReachHere();
   }
 }
 
+// Keep the nmethod for compiled_method_load from being unloaded.
+void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) {
+  if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
+    cf->do_code_blob(_event_data.compiled_method_load);
+  }
+}
+
+// The sweeper calls this and marks the nmethods here on the stack so that
+// they cannot be turned into zombies while in the queue.
+void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) {
+  if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
+    cf->do_code_blob(_event_data.compiled_method_load);
+  }  // May add UNLOAD event but it doesn't work yet.
+}
+
 JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_tail = NULL;
 JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_head = NULL;
 
@@ -1029,3 +1060,15 @@
   delete node;
   return event;
 }
+
+void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) {
+  for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
+     node->event().oops_do(f, cf);
+  }
+}
+
+void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) {
+  for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
+     node->event().nmethods_do(cf);
+  }
+}
--- a/src/hotspot/share/prims/jvmtiImpl.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/prims/jvmtiImpl.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -440,7 +440,8 @@
     TYPE_NONE,
     TYPE_COMPILED_METHOD_LOAD,
     TYPE_COMPILED_METHOD_UNLOAD,
-    TYPE_DYNAMIC_CODE_GENERATED
+    TYPE_DYNAMIC_CODE_GENERATED,
+    TYPE_CLASS_UNLOAD
   } Type;
 
   Type _type;
@@ -456,6 +457,9 @@
       const void* code_begin;
       const void* code_end;
     } dynamic_code_generated;
+    struct {
+      const char* name;
+    } class_unload;
   } _event_data;
 
   JvmtiDeferredEvent(Type t) : _type(t) {}
@@ -472,9 +476,15 @@
   static JvmtiDeferredEvent dynamic_code_generated_event(
       const char* name, const void* begin, const void* end)
           NOT_JVMTI_RETURN_(JvmtiDeferredEvent());
+  static JvmtiDeferredEvent class_unload_event(
+      const char* name) NOT_JVMTI_RETURN_(JvmtiDeferredEvent());
 
   // Actually posts the event.
   void post() NOT_JVMTI_RETURN;
+  // Sweeper support to keep nmethods from being zombied while in the queue.
+  void nmethods_do(CodeBlobClosure* cf) NOT_JVMTI_RETURN;
+  // GC support to keep nmethod from being unloaded while in the queue.
+  void oops_do(OopClosure* f, CodeBlobClosure* cf) NOT_JVMTI_RETURN;
 };
 
 /**
@@ -494,7 +504,7 @@
     QueueNode(const JvmtiDeferredEvent& event)
       : _event(event), _next(NULL) {}
 
-    const JvmtiDeferredEvent& event() const { return _event; }
+    JvmtiDeferredEvent& event() { return _event; }
     QueueNode* next() const { return _next; }
 
     void set_next(QueueNode* next) { _next = next; }
@@ -508,6 +518,10 @@
   static bool has_events() NOT_JVMTI_RETURN_(false);
   static void enqueue(const JvmtiDeferredEvent& event) NOT_JVMTI_RETURN;
   static JvmtiDeferredEvent dequeue() NOT_JVMTI_RETURN_(JvmtiDeferredEvent());
+  // Sweeper support to keep nmethods from being zombied while in the queue.
+  static void nmethods_do(CodeBlobClosure* cf) NOT_JVMTI_RETURN;
+  // GC support to keep nmethod from being unloaded while in the queue.
+  static void oops_do(OopClosure* f, CodeBlobClosure* cf) NOT_JVMTI_RETURN;
 };
 
 // Utility macro that checks for NULL pointers:
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -244,7 +244,7 @@
     Notification_lock = Service_lock;
   }
 
-  def(JmethodIdCreation_lock       , PaddedMutex  , leaf,        true,  _safepoint_check_always); // used for creating jmethodIDs.
+  def(JmethodIdCreation_lock       , PaddedMutex  , leaf,        true,  _safepoint_check_never); // used for creating jmethodIDs.
 
   def(SystemDictionary_lock        , PaddedMonitor, leaf,        true,  _safepoint_check_always);
   def(ProtectionDomainSet_lock     , PaddedMutex  , leaf-1,      true,  _safepoint_check_never);
--- a/src/hotspot/share/runtime/serviceThread.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/serviceThread.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -46,6 +46,7 @@
 #include "services/threadIdTable.hpp"
 
 ServiceThread* ServiceThread::_instance = NULL;
+JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
 
 void ServiceThread::initialize() {
   EXCEPTION_MARK;
@@ -138,7 +139,9 @@
       }
 
       if (has_jvmti_events) {
+        // Get the event under the Service_lock
         jvmti_event = JvmtiDeferredEventQueue::dequeue();
+        _jvmti_event = &jvmti_event;
       }
     }
 
@@ -151,7 +154,8 @@
     }
 
     if (has_jvmti_events) {
-      jvmti_event.post();
+      _jvmti_event->post();
+      _jvmti_event = NULL;  // reset
     }
 
     if (!UseNotificationThread) {
@@ -186,6 +190,26 @@
   }
 }
 
-bool ServiceThread::is_service_thread(Thread* thread) {
-  return thread == _instance;
+void ServiceThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
+  JavaThread::oops_do(f, cf);
+  // The ServiceThread "owns" the JVMTI Deferred events, scan them here
+  // to keep them alive until they are processed.
+  if (cf != NULL) {
+    if (_jvmti_event != NULL) {
+      _jvmti_event->oops_do(f, cf);
+    }
+    MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
+    JvmtiDeferredEventQueue::oops_do(f, cf);
+  }
 }
+
+void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
+  JavaThread::nmethods_do(cf);
+  if (cf != NULL) {
+    if (_jvmti_event != NULL) {
+      _jvmti_event->nmethods_do(cf);
+    }
+    MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
+    JvmtiDeferredEventQueue::nmethods_do(cf);
+  }
+}
--- a/src/hotspot/share/runtime/serviceThread.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/serviceThread.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -30,12 +30,13 @@
 // A hidden from external view JavaThread for JVMTI compiled-method-load
 // events, oop storage cleanup, and the maintainance of string, symbol,
 // protection domain, and resolved method tables.
+class JvmtiDeferredEvent;
 
 class ServiceThread : public JavaThread {
   friend class VMStructs;
  private:
-
   static ServiceThread* _instance;
+  static JvmtiDeferredEvent* _jvmti_event;
 
   static void service_thread_entry(JavaThread* thread, TRAPS);
   ServiceThread(ThreadFunction entry_point) : JavaThread(entry_point) {};
@@ -45,9 +46,11 @@
 
   // Hide this thread from external view.
   bool is_hidden_from_external_view() const      { return true; }
+  bool is_service_thread() const                 { return true; }
 
-  // Returns true if the passed thread is the service thread.
-  static bool is_service_thread(Thread* thread);
+  // GC support
+  void oops_do(OopClosure* f, CodeBlobClosure* cf);
+  void nmethods_do(CodeBlobClosure* cf);
 };
 
 #endif // SHARE_RUNTIME_SERVICETHREAD_HPP
--- a/src/hotspot/share/runtime/thread.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/thread.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1649,7 +1649,7 @@
   set_deopt_compiled_method(NULL);
   set_monitor_chunks(NULL);
   _on_thread_list = false;
-  set_thread_state(_thread_new);
+  _thread_state = _thread_new;
   _terminated = _not_terminated;
   _array_for_gc = NULL;
   _suspend_equivalent = false;
--- a/src/hotspot/share/runtime/thread.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/thread.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -480,6 +480,7 @@
   virtual bool is_Java_thread()     const            { return false; }
   virtual bool is_Compiler_thread() const            { return false; }
   virtual bool is_Code_cache_sweeper_thread() const  { return false; }
+  virtual bool is_service_thread() const             { return false; }
   virtual bool is_hidden_from_external_view() const  { return false; }
   virtual bool is_jvmti_agent_thread() const         { return false; }
   // True iff the thread can perform GC operations at a safepoint.
--- a/src/hotspot/share/runtime/thread.inline.hpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/hotspot/share/runtime/thread.inline.hpp	Tue Dec 03 12:45:47 2019 +0530
@@ -125,6 +125,8 @@
 }
 
 inline void JavaThread::set_thread_state(JavaThreadState s) {
+  assert(current_or_null() == NULL || current_or_null() == this,
+         "state change should only be called by the current thread");
 #if defined(PPC64) || defined (AARCH64)
   // Use membars when accessing volatile _thread_state. See
   // Threads::create_vm() for size checks.
--- a/src/java.base/share/classes/java/time/overview.html	Mon Dec 02 16:38:34 2019 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-<!--
-/*
- * Copyright (c) 2012, 2013, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- *  * Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- *  * Neither the name of JSR-310 nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
--->
-<body>
-    <p>
-        A new Date and Time API for Java.
-        The design includes a relatively large number of classes and methods,
-        however each follows a common design language, especially in method prefixes.
-        Once the prefixes are understood, the API is relatively simple to comprehend.
-    </p>
-    <p>
-        The Java Time API is composed of several packages, each with a primary function:
-    </p>
-    <p>
-        {@link java.time} contains the main API based on the ISO-8601 standard.
-        The classes defined here represent the principal date-time concepts,
-        including instants, durations, dates, times, time-zones and periods.
-        They are based on the ISO calendar system, which is the <i>de facto</i> world
-        calendar following the proleptic Gregorian rules.
-        All the classes are immutable and thread-safe.
-    </p>
-    <p>
-        {@link java.time.temporal} contains the API for accessing the fields and units
-        of date-time. Units are measurable, such as years, months and hours.
-        For example, the expression "2 hours later" uses the hours unit.
-        By contrast, fields are mini-calculations, defining a value.
-        For example, month-of-year, day-of-week and hour-of-day are all fields.
-        The set of supported units and fields can be extended by applications if desired.
-    </p>
-    <p>
-        {@link java.time.format} contains the API to print and parse fields into date-time
-        objects and to customize parsing and printing.
-        Formatters can be created in a variety of ways, including constants, patterns,
-        localized styles and a builder.
-        Formatters are immutable and thread-safe.
-    </p>
-    <p>
-        {@link java.time.zone} contains the API to handle time-zones.
-        Detailed information is made available about the rules of each time-zone.
-    </p>
-    <p>
-        {@link java.time.chrono} contains the basic part of the calendar neutral API
-        and alternate calendar systems.
-        This is intended for use by applications that need to use localized calendars.
-        Support is provided for the Hijrah, Japanese, Minguo, and Thai Buddhist Calendars.
-    </p>
-    <h3>Design notes</h3>
-    <p>
-        Where possible, the API avoids the use of null.
-        All methods define whether they accept or return null in the Javadoc.
-        As a general rule, methods do not accept or return null.
-        A key exception is any method that takes an object and returns a boolean, for the purpose
-        of checking or validating, will generally return false for null.
-    </p>
-    <p>
-        The API is designed to be type-safe where reasonable in the main high-level API.
-        Thus, there are separate classes for the distinct concepts of date, time and date-time, plus variants
-        for offset and time-zones. The core 7 date-time classes, plus Instant, handle the needs of most applications.
-        Further classes handle other combinations - year, year-month and month-day in a type-safe manner.
-    </p>
-    <p>
-        In a language like Java, the use of many different types tends to cause API bloat.
-        This is handled here through the use of common method naming patterns throughout the API.
-        The common prefixes are 'of', 'get', 'is', 'with', 'plus', 'minus', 'to' and 'at'.
-        See {@link java.time.LocalDate} for an example of each of these methods.
-    </p>
-    <p>
-        Following type-safety to its logical conclusion would result in more classes, especially for time -
-        hour-minute, hour-minute-second and hour-minute-second-nanosecond.
-        While logically pure, this was not possible in practice, as the additional classes would have
-        excessively complicated the API. Notably, there would be additional combinations at the offset
-        and date-time levels, such as offset-date-hour-minute.
-        To avoid this explosion of types, {@link java.time.LocalTime} is used for all precisions of time.
-        By contrast, some additional classes were used for dates, such as {@link java.time.YearMonth}.
-        This proved necessary, as the API for year-month is significantly different to that for a date, whereas
-        an absence of nanoseconds in a time can be approximated by returning zero.
-    </p>
-    <p>
-        Similarly, full type-safety might argue for a separate class for each field in date-time,
-        such as a class for HourOfDay and another for DayOfMonth.
-        This approach was tried, but was excessively complicated in the Java language, lacking usability.
-        A similar problem occurs with periods.
-        There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes.
-        However, this yields a lot of classes and a problem of type conversion.
-        As such, general access to fields and units is not wrapped in a class.
-    </p>
-    <p>
-        Multiple calendar systems is an awkward addition to the design challenges.
-        The first principal is that most users want the standard ISO calendar system.
-        As such, the main classes are ISO-only. The second principal is that most of those that want a
-        non-ISO calendar system want it for user interaction, thus it is a UI localization issue.
-        As such, date and time objects should be held as ISO objects in the data model and persistent
-        storage, only being converted to and from a local calendar for display.
-        The calendar system would be stored separately in the user preferences.
-    </p>
-    <p>
-        There are, however, some limited use cases where users believe they need to store and use
-        dates in arbitrary calendar systems throughout the application.
-        This is supported by {@link java.time.chrono.ChronoLocalDate}, however it is vital to read
-        all the associated warnings in the Javadoc of that interface before using it.
-        In summary, applications that require general interoperation between multiple calendar systems
-        typically need to be written in a very different way to those only using the ISO calendar,
-        thus most applications should just use ISO and avoid {@code ChronoLocalDate}.
-    </p>
-    <p>
-        Throughout all of this, a key goal was to allow date-time fields and units to be defined by applications.
-        This has been achieved having tried many different designs.
-    </p>
-</body>
--- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java	Tue Dec 03 12:45:47 2019 +0530
@@ -254,10 +254,10 @@
         AlgorithmParameters algParams = null;
         boolean mediator = (keAlgParamSpec != null);
 
-        // HACK CODE
-        //
         // An EC provider, for example the SunEC provider, may support
         // AlgorithmParameters but not KeyPairGenerator or KeyAgreement.
+        //
+        // Note: Please be careful if removing this block!
         if (mediator && (namedGroupSpec == NamedGroupSpec.NAMED_GROUP_ECDHE)) {
             mediator = JsseJce.isEcAvailable();
         }
@@ -277,10 +277,10 @@
                             "No AlgorithmParameters for " + name, exp);
                     }
                 } else {
-                    // HACK CODE
-                    //
                     // Please remove the following code if the XDH/X25519/X448
                     // AlgorithmParameters algorithms are supported in JDK.
+                    //
+                    // Note: Please be careful if removing this block!
                     algParams = null;
                     try {
                         KeyAgreement.getInstance(name);
--- a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java	Tue Dec 03 12:45:47 2019 +0530
@@ -381,7 +381,7 @@
                             "Requested to negotiate unsupported SSLv2!");
                 }
 
-                // hack code, the exception is caught in SSLEngineImpl
+                // Note that the exception is caught in SSLEngineImpl
                 // so that SSLv2 error message can be delivered properly.
                 throw new UnsupportedOperationException(        // SSLv2Hello
                         "Unsupported SSL v2.0 ClientHello");
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Tue Dec 03 12:45:47 2019 +0530
@@ -274,10 +274,10 @@
                 Arrays.asList(handshakeSupportedProtocols);
 
         boolean mediator = true;
-        // HACK CODE
-        //
         // An EC provider, for example the SunEC provider, may support
         // AlgorithmParameters but not KeyPairGenerator or Signature.
+        //
+        // Note: Please be careful if removing this block!
         if ("EC".equals(keyAlgorithm)) {
             mediator = JsseJce.isEcAvailable();
         }
--- a/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java	Tue Dec 03 12:45:47 2019 +0530
@@ -217,9 +217,9 @@
             try {
                 @SuppressWarnings("deprecation")
                 KeyStoreSpi tmp = primaryKeyStore.newInstance();
+                tmp.engineLoad(bufferedStream, password);
                 keystore = tmp;
                 type = primaryType;
-                keystore.engineLoad(bufferedStream, password);
 
             } catch (Exception e) {
 
@@ -236,11 +236,11 @@
                     }
 
                     @SuppressWarnings("deprecation")
-                    KeyStoreSpi tmp= secondaryKeyStore.newInstance();
+                    KeyStoreSpi tmp = secondaryKeyStore.newInstance();
+                    bufferedStream.reset();
+                    tmp.engineLoad(bufferedStream, password);
                     keystore = tmp;
                     type = secondaryType;
-                    bufferedStream.reset();
-                    keystore.engineLoad(bufferedStream, password);
 
                     if (debug != null) {
                         debug.println("WARNING: switching from " +
--- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor7.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor7.java	Tue Dec 03 12:45:47 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2019, Oacle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
--- a/src/jdk.compiler/share/classes/META-INF/services/com.sun.tools.javac.platform.PlatformProvider	Mon Dec 02 16:38:34 2019 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-com.sun.tools.javac.platform.JDKPlatformProvider
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Dec 03 12:45:47 2019 +0530
@@ -953,7 +953,7 @@
 # {1} - current module
 # 0: symbol, 1: symbol
 compiler.misc.not.def.access.does.not.read.unnamed=\
-    package {0} is declared in the unnamed module, but module {0} does not read it
+    package {0} is declared in the unnamed module, but module {1} does not read it
 
 # {0} - package in which the invisible class is declared
 # {1} - module in which {0} is declared
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/services/javax.tools.JavaCompilerTool	Mon Dec 02 16:38:34 2019 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-com.sun.tools.javac.api.Tool
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java	Tue Dec 03 12:45:47 2019 +0530
@@ -54,6 +54,12 @@
 
     private final Navigation navBar;
 
+    private final String[][] SEARCH_EXAMPLES = {
+            {"j.l.obj", "\"java.lang.Object\""},
+            {"InpStr", "\"java.io.InputStream\""},
+            {"HM.cK", "\"java.util.HashMap.containsKey(Object)\""}
+    };
+
     /**
      * Constructor to construct HelpWriter object.
      * @param configuration the configuration
@@ -326,9 +332,20 @@
         Content searchHead = HtmlTree.HEADING(Headings.CONTENT_HEADING,
                 contents.getContent("doclet.help.search.head"));
         htmlTree = HtmlTree.SECTION(HtmlStyle.helpSection, searchHead);
-        Content searchBody = contents.getContent("doclet.help.search.body");
-        Content searchPara = HtmlTree.P(searchBody);
-        htmlTree.add(searchPara);
+        Content searchIntro = HtmlTree.P(contents.getContent("doclet.help.search.intro"));
+        Content searchExamples = new HtmlTree(HtmlTag.UL);
+        for (String[] example : SEARCH_EXAMPLES) {
+            searchExamples.add(HtmlTree.LI(
+                    contents.getContent("doclet.help.search.example",
+                            HtmlTree.CODE(new StringContent(example[0])), example[1])));
+        }
+        Content searchSpecLink = HtmlTree.A(
+                resources.getText("doclet.help.search.spec.url", Runtime.version().feature()),
+                contents.getContent("doclet.help.search.spec.title"));
+        Content searchRefer = HtmlTree.P(contents.getContent("doclet.help.search.refer", searchSpecLink));
+        htmlTree.add(searchIntro);
+        htmlTree.add(searchExamples);
+        htmlTree.add(searchRefer);
         ul.add(HtmlTree.LI(HtmlStyle.blockList, htmlTree));
 
         Content divContent = HtmlTree.DIV(HtmlStyle.contentContainer, ul);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Mon Dec 02 16:38:34 2019 -0800
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Tue Dec 03 12:45:47 2019 +0530
@@ -215,9 +215,18 @@
 doclet.help.annotation_type.description=\
     Annotation Type Description
 doclet.help.search.head=Search
-doclet.help.search.body=You can search for definitions of modules, packages, types, fields, methods \
-    and other terms defined in the API, using some or all of the name. "Camel-case" abbreviations \
-    are supported: for example, "InpStr" will find "InputStream" and "InputStreamReader".
+# Introduction to Javadoc search features, followed by a list of examples
+doclet.help.search.intro=You can search for definitions of modules, packages, types, fields, methods, \
+    system properties and other terms defined in the API, using some or all of the name, optionally \
+    using "camel-case" abbreviations. For example:
+# Used to list search examples, {0} is a search term and {1} the matching result
+doclet.help.search.example={0} will match {1}
+# {0} contains a link to the current Javadoc Search Specification
+doclet.help.search.refer=Refer to {0} for a full description of search features.
+# The URL for the Javadoc Search Specification. {0} will be replaced by the JDK version number
+doclet.help.search.spec.url=https://docs.oracle.com/en/java/javase/{0}/docs/specs/javadoc/javadoc-search-spec.html
+# The title for the Javadoc Search Specification
+doclet.help.search.spec.title=the Javadoc Search Specification
 
 doclet.ClassUse_Packages.that.use.0=Packages that use {0}
 doclet.ClassUse_Uses.of.0.in.1=Uses of {0} in {1}
--- a/test/hotspot/gtest/gc/g1/test_g1Predictions.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/test/hotspot/gtest/gc/g1/test_g1Predictions.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 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
@@ -35,17 +35,17 @@
   G1Predictions predictor(0.0);
   TruncatedSeq s;
 
-  double p0 = predictor.get_new_prediction(&s);
+  double p0 = predictor.predict(&s);
   ASSERT_LT(p0, epsilon) << "Initial prediction of empty sequence must be 0.0";
 
   s.add(5.0);
-  double p1 = predictor.get_new_prediction(&s);
+  double p1 = predictor.predict(&s);
   ASSERT_NEAR(p1, 5.0, epsilon);
 
   for (int i = 0; i < 40; i++) {
     s.add(5.0);
   }
-  double p2 = predictor.get_new_prediction(&s);
+  double p2 = predictor.predict(&s);
   ASSERT_NEAR(p2, 5.0, epsilon);
 }
 
@@ -56,20 +56,20 @@
   TruncatedSeq s;
 
   s.add(1.0);
-  double p1 = predictor.get_new_prediction(&s);
+  double p1 = predictor.predict(&s);
   ASSERT_GT(p1, s.davg()) << "First prediction must be greater than average";
 
   s.add(1.0);
-  double p2 = predictor.get_new_prediction(&s);
+  double p2 = predictor.predict(&s);
   ASSERT_GT(p1, p2) << "First prediction must be greater than second";
 
   s.add(1.0);
-  double p3 = predictor.get_new_prediction(&s);
+  double p3 = predictor.predict(&s);
   ASSERT_GT(p2, p3) << "Second prediction must be greater than third";
 
   s.add(1.0);
   s.add(1.0); // Five elements are now in the sequence.
-  double p4 = predictor.get_new_prediction(&s);
+  double p4 = predictor.predict(&s);
   ASSERT_LT(p4, p3) << "Fourth prediction must be smaller than third";
   ASSERT_NEAR(p4, 1.0, epsilon);
 }
@@ -82,20 +82,20 @@
   TruncatedSeq s;
 
   s.add(0.5);
-  double p1 = predictor.get_new_prediction(&s);
+  double p1 = predictor.predict(&s);
   ASSERT_GT(p1, s.davg()) << "First prediction must be greater than average";
 
   s.add(0.2);
-  double p2 = predictor.get_new_prediction(&s);
+  double p2 = predictor.predict(&s);
   ASSERT_GT(p1, p2) << "First prediction must be greater than second";
 
   s.add(0.5);
-  double p3 = predictor.get_new_prediction(&s);
+  double p3 = predictor.predict(&s);
   ASSERT_GT(p2, p3) << "Second prediction must be greater than third";
 
   s.add(0.2);
   s.add(2.0);
-  double p4 = predictor.get_new_prediction(&s);
+  double p4 = predictor.predict(&s);
   ASSERT_GT(p4, p3) << "Fourth prediction must be greater than third";
 }
 
@@ -104,24 +104,24 @@
   G1Predictions predictor(0.5);
   TruncatedSeq s;
 
-  double p0 = predictor.get_new_unit_prediction(&s);
+  double p0 = predictor.predict_in_unit_interval(&s);
   ASSERT_LT(p0, epsilon) << "Initial prediction of empty sequence must be 0.0";
 
   s.add(100.0);
-  double p1 = predictor.get_new_unit_prediction(&s);
+  double p1 = predictor.predict_in_unit_interval(&s);
   ASSERT_NEAR(p1, 1.0, epsilon);
 
   // Feed the sequence additional positive values to test the high bound.
   for (int i = 0; i < 3; i++) {
     s.add(2.0);
   }
-  ASSERT_NEAR(predictor.get_new_unit_prediction(&s), 1.0, epsilon);
+  ASSERT_NEAR(predictor.predict_in_unit_interval(&s), 1.0, epsilon);
 
   // Feed the sequence additional large negative value to test the low bound.
   for (int i = 0; i < 4; i++) {
     s.add(-200.0);
   }
-  ASSERT_NEAR(predictor.get_new_unit_prediction(&s), 0.0, epsilon);
+  ASSERT_NEAR(predictor.predict_in_unit_interval(&s), 0.0, epsilon);
 }
 
 // Some tests to verify bounding between [0 .. +inf]
@@ -129,7 +129,7 @@
   G1Predictions predictor(0.5);
   TruncatedSeq s;
 
-  double p0 = predictor.get_new_lower_zero_bound_prediction(&s);
+  double p0 = predictor.predict_zero_bounded(&s);
   ASSERT_LT(p0, epsilon) << "Initial prediction of empty sequence must be 0.0";
 
   s.add(100.0);
@@ -138,11 +138,11 @@
   for (int i = 0; i < 3; i++) {
     s.add(2.0);
   }
-  ASSERT_GT(predictor.get_new_lower_zero_bound_prediction(&s), 1.0);
+  ASSERT_GT(predictor.predict_zero_bounded(&s), 1.0);
 
   // Feed the sequence additional large negative value to test the low bound.
   for (int i = 0; i < 4; i++) {
     s.add(-200.0);
   }
-  ASSERT_NEAR(predictor.get_new_lower_zero_bound_prediction(&s), 0.0, epsilon);
+  ASSERT_NEAR(predictor.predict_zero_bounded(&s), 0.0, epsilon);
 }
--- a/test/hotspot/jtreg/ProblemList.txt	Mon Dec 02 16:38:34 2019 -0800
+++ b/test/hotspot/jtreg/ProblemList.txt	Tue Dec 03 12:45:47 2019 +0530
@@ -178,7 +178,6 @@
 
 vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003/TestDescription.java 6606767 generic-all
 vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted004/TestDescription.java 6606767 generic-all
-vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/TestDescription.java 8173658 generic-all
 vmTestbase/nsk/jvmti/AttachOnDemand/attach045/TestDescription.java 8202971 generic-all
 vmTestbase/nsk/jvmti/scenarios/jni_interception/JI05/ji05t001/TestDescription.java 8219652 aix-ppc64
 vmTestbase/nsk/jvmti/scenarios/jni_interception/JI06/ji06t001/TestDescription.java 8219652 aix-ppc64
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/ex03t001.cpp	Mon Dec 02 16:38:34 2019 -0800
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/extension/EX03/ex03t001/ex03t001.cpp	Tue Dec 03 12:45:47 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -41,18 +41,15 @@
 /* ============================================================================= */
 
 static void JNICALL
-ClassUnload(jvmtiEnv* jvmti_env, JNIEnv *jni_env, jthread thread, jclass klass, ...) {
-    /*
-     * With the CMS GC the event can be posted on
-     * a ConcurrentGC thread that is not a JavaThread.
-     * In this case the thread argument can be NULL, so that,
-     * we should not expect the thread argument to be non-NULL.
-     */
-    if (klass == NULL) {
+ClassUnload(jvmtiEnv* jvmti_env, JNIEnv* jni_env, const char* name, ...) {
+    // The name argument should never be null
+    if (name == NULL) {
         nsk_jvmti_setFailStatus();
-        NSK_COMPLAIN0("ClassUnload: 'klass' input parameter is NULL.\n");
+        NSK_COMPLAIN0("ClassUnload: 'name' input parameter is NULL.\n");
+    } else {
+        NSK_DISPLAY1("Class unloaded %s\n", name);
+    }
 
-    }
     NSK_DISPLAY0("Received ClassUnload event.\n");
     if (eventEnabled == JNI_TRUE) {
         eventReceived1 = JNI_TRUE;
@@ -107,6 +104,20 @@
     return enabled;
 }
 
+jboolean checkParams(jvmtiExtensionEventInfo event) {
+    // Check parameters are:
+    // JNIEnv *jni_env, const char* name
+    if (event.param_count != 2 ||
+          event.params[0].kind != JVMTI_KIND_IN_PTR ||
+          event.params[0].base_type != JVMTI_TYPE_JNIENV ||
+          event.params[1].kind != JVMTI_KIND_IN_PTR ||
+          event.params[1].base_type != JVMTI_TYPE_CCHAR) {
+        return JNI_FALSE;
+    } else {
+        return JNI_TRUE;
+    }
+}
+
 jboolean enableClassUnloadEvent (jboolean enable) {
     jint extCount, i;
     jvmtiExtensionEventInfo* extList;
@@ -122,6 +133,14 @@
         if (strcmp(extList[i].id, (char*)"com.sun.hotspot.events.ClassUnload") == 0) {
             found = JNI_TRUE;
 
+            NSK_DISPLAY1("%s", extList[i].short_description);
+
+            if (!checkParams(extList[i])) {
+                NSK_COMPLAIN0("ClassUnload event has wrong parameters.");
+                nsk_jvmti_setFailStatus();
+                return JNI_FALSE;
+            }
+
             if (!NSK_JVMTI_VERIFY(
                     jvmti->SetExtensionEventCallback(extList[i].extension_event_index,
                                                      enable ? (jvmtiExtensionEvent)ClassUnload : NULL))) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/provider/KeyStore/WrongStoreType.java	Tue Dec 03 12:45:47 2019 +0530
@@ -0,0 +1,66 @@
+/*
+ * 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 8234744
+ * @summary KeyStore.store can write wrong type of file
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+
+public class WrongStoreType {
+    public static void main(String ... args) throws Exception {
+
+        char[] password = "changeit".toCharArray();
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+
+        ks.load(null, null);
+        System.out.println(ks.getType());
+
+        Files.createFile(Path.of("emptyfile"));
+        try (InputStream in = new FileInputStream("emptyfile")) {
+            ks.load(in, password);
+        } catch (Exception e) {
+            System.out.println(e);
+        }
+
+        System.out.println(ks.getType());
+        try (OutputStream out = new FileOutputStream("newfile")) {
+            ks.store(out, password);
+        }
+
+        ks = KeyStore.getInstance(new File("newfile"), password);
+        String type = ks.getType();
+        if (!type.equalsIgnoreCase("PKCS12")) {
+            throw new Exception("see storetype " + type);
+        }
+    }
+}