changeset 11233:f2a0c035835b

Merge
author vlivanov
date Tue, 10 May 2016 21:38:44 +0000
parents cf3f7ec2a1c7 8e3c3195f07f
children b2f17e1250fd
files
diffstat 10 files changed, 217 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java	Wed May 11 00:31:28 2016 +0300
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java	Tue May 10 21:38:44 2016 +0000
@@ -73,6 +73,7 @@
         System.out.println("    <no option>\tto print same info as Solaris pmap");
         System.out.println("    --heap\tto print java heap summary");
         System.out.println("    --binaryheap\tto dump java heap in hprof binary format");
+        System.out.println("    --dumpfile\tname of the dump file");
         System.out.println("    --histo\tto print histogram of java object heap");
         System.out.println("    --clstats\tto print class loader statistics");
         System.out.println("    --finalizerinfo\tto print information on objects awaiting finalization");
@@ -241,13 +242,15 @@
     private static void runJMAP(String[] oldArgs) {
         SAGetopt sg = new SAGetopt(oldArgs);
         String[] longOpts = {"exe=", "core=", "pid=",
-              "heap", "binaryheap", "histo", "clstats", "finalizerinfo"};
+              "heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
 
         ArrayList<String> newArgs = new ArrayList();
         String pid = null;
         String exe = null;
         String core = null;
         String s = null;
+        String dumpfile = null;
+        boolean requestHeapdump = false;
 
         while((s = sg.next(null, longOpts)) != null) {
             if (s.equals("exe")) {
@@ -267,7 +270,11 @@
                 continue;
             }
             if (s.equals("binaryheap")) {
-                newArgs.add("-heap:format=b");
+                requestHeapdump = true;
+                continue;
+            }
+            if (s.equals("dumpfile")) {
+                dumpfile = sg.getOptarg();
                 continue;
             }
             if (s.equals("histo")) {
@@ -284,6 +291,17 @@
             }
         }
 
+        if (!requestHeapdump && (dumpfile != null)) {
+            throw new IllegalArgumentException("Unexpected argument dumpfile");
+        }
+        if (requestHeapdump) {
+            if (dumpfile == null) {
+                newArgs.add("-heap:format=b");
+            } else {
+                newArgs.add("-heap:format=b,file=" + dumpfile);
+            }
+        }
+
         buildAttachArgs(newArgs, pid, exe, core, false);
         JMap.main(newArgs.toArray(new String[newArgs.size()]));
     }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java	Wed May 11 00:31:28 2016 +0300
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java	Tue May 10 21:38:44 2016 +0000
@@ -71,6 +71,8 @@
     public static final int MODE_HEAP_GRAPH_GXL = 5;
     public static final int MODE_FINALIZERINFO = 6;
 
+    private static String dumpfile = "heap.bin";
+
     public void run() {
         Tool tool = null;
         switch (mode) {
@@ -92,11 +94,11 @@
             break;
 
         case MODE_HEAP_GRAPH_HPROF_BIN:
-            writeHeapHprofBin();
+            writeHeapHprofBin(dumpfile);
             return;
 
         case MODE_HEAP_GRAPH_GXL:
-            writeHeapGXL();
+            writeHeapGXL(dumpfile);
             return;
 
         case MODE_FINALIZERINFO:
@@ -127,18 +129,34 @@
             } else if (modeFlag.equals("-finalizerinfo")) {
                 mode = MODE_FINALIZERINFO;
             } else {
-                int index = modeFlag.indexOf("-heap:format=");
+                int index = modeFlag.indexOf("-heap:");
                 if (index != -1) {
-                    String format = modeFlag.substring(1 + modeFlag.indexOf('='));
-                    if (format.equals("b")) {
-                        mode = MODE_HEAP_GRAPH_HPROF_BIN;
-                    } else if (format.equals("x")) {
-                        mode = MODE_HEAP_GRAPH_GXL;
-                    } else {
-                        System.err.println("unknown heap format:" + format);
+                    String[] options = modeFlag.substring(6).split(",");
+                    for (String option : options) {
+                        String[] keyValue = option.split("=");
+                        if (keyValue[0].equals("format")) {
+                            if (keyValue[1].equals("b")) {
+                                mode = MODE_HEAP_GRAPH_HPROF_BIN;
+                            } else if (keyValue[1].equals("x")) {
+                                mode = MODE_HEAP_GRAPH_GXL;
+                            } else {
+                                System.err.println("unknown heap format:" + keyValue[0]);
 
-                        // Exit with error status
-                        System.exit(1);
+                                // Exit with error status
+                                System.exit(1);
+                            }
+                        } else if (keyValue[0].equals("file")) {
+                            if ((keyValue[1] == null) || keyValue[1].equals("")) {
+                                System.err.println("File name must be set.");
+                                System.exit(1);
+                            }
+                            dumpfile = keyValue[1];
+                        } else {
+                            System.err.println("unknown option:" + keyValue[0]);
+
+                            // Exit with error status
+                            System.exit(1);
+                        }
                     }
                 } else {
                     copyArgs = false;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java	Wed May 11 00:31:28 2016 +0300
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/JavaThreadsPanel.java	Tue May 10 21:38:44 2016 +0000
@@ -39,6 +39,7 @@
 
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
 
 import sun.jvm.hotspot.ui.action.*;
 
@@ -55,9 +56,19 @@
     private JavaThreadsTableModel dataModel;
     private StatusBar statusBar;
     private JTable     threadTable;
-    private java.util.List cachedThreads = new ArrayList();
+    private java.util.List<CachedThread> cachedThreads = new ArrayList();
+    private static AddressField crashThread;
 
 
+    static {
+        VM.registerVMInitializedObserver(
+                            (o, a) -> initialize(VM.getVM().getTypeDataBase()));
+    }
+
+    private static void initialize(TypeDataBase db) {
+        crashThread = db.lookupType("VMError").getAddressField("_thread");
+    }
+
     /** Constructor assumes the threads panel is created while the VM is
         suspended. Subsequent resume and suspend operations of the VM
         will cause the threads panel to clear and fill itself back in,
@@ -437,21 +448,14 @@
      * @return a flag which indicates if crashes were encountered.
      */
     private boolean fireShowThreadCrashes() {
-        boolean crash = false;
-        for (Iterator iter = cachedThreads.iterator(); iter.hasNext(); ) {
-            JavaThread t = (JavaThread) ((CachedThread) iter.next()).getThread();
-            sun.jvm.hotspot.runtime.Frame tmpFrame = t.getCurrentFrameGuess();
-            RegisterMap tmpMap = t.newRegisterMap(false);
-            while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
-                if (tmpFrame.isSignalHandlerFrameDbg()) {
-                    showThreadStackMemory(t);
-                    crash = true;
-                    break;
-                }
-                tmpFrame = tmpFrame.sender(tmpMap);
-            }
-        }
-        return crash;
+        Optional<JavaThread> crashed =
+                         cachedThreads.stream()
+                                      .map(t -> t.getThread())
+                                      .filter(t -> t.getAddress().equals(
+                                                        crashThread.getValue()))
+                                      .findAny();
+        crashed.ifPresent(this::showThreadStackMemory);
+        return crashed.isPresent();
     }
 
     private void cache() {
--- a/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Tue May 10 21:38:44 2016 +0000
@@ -273,7 +273,7 @@
 
   // Currently, only survivors can be root regions.
   _claimed_survivor_index = 0;
-  _scan_in_progress = true;
+  _scan_in_progress = _survivors->regions()->is_nonempty();
   _should_abort = false;
 }
 
@@ -294,6 +294,10 @@
   return NULL;
 }
 
+uint G1CMRootRegions::num_root_regions() const {
+  return (uint)_survivors->regions()->length();
+}
+
 void G1CMRootRegions::notify_scan_done() {
   MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
   _scan_in_progress = false;
@@ -912,15 +916,16 @@
     n_conc_workers = max_parallel_marking_threads();
   } else {
     n_conc_workers =
-      AdaptiveSizePolicy::calc_default_active_workers(
-                                   max_parallel_marking_threads(),
-                                   1, /* Minimum workers */
-                                   parallel_marking_threads(),
-                                   Threads::number_of_non_daemon_threads());
+      AdaptiveSizePolicy::calc_default_active_workers(max_parallel_marking_threads(),
+                                                      1, /* Minimum workers */
+                                                      parallel_marking_threads(),
+                                                      Threads::number_of_non_daemon_threads());
     // Don't scale down "n_conc_workers" by scale_parallel_threads() because
     // that scaling has already gone into "_max_parallel_marking_threads".
   }
-  assert(n_conc_workers > 0, "Always need at least 1");
+  assert(n_conc_workers > 0 && n_conc_workers <= max_parallel_marking_threads(),
+         "Calculated number of workers must be larger than zero and at most the maximum %u, but is %u",
+         max_parallel_marking_threads(), n_conc_workers);
   return n_conc_workers;
 }
 
@@ -947,7 +952,7 @@
 
 public:
   G1CMRootRegionScanTask(G1ConcurrentMark* cm) :
-    AbstractGangTask("Root Region Scan"), _cm(cm) { }
+    AbstractGangTask("G1 Root Region Scan"), _cm(cm) { }
 
   void work(uint worker_id) {
     assert(Thread::current()->is_ConcurrentGC_thread(),
@@ -969,14 +974,17 @@
   if (root_regions()->scan_in_progress()) {
     assert(!has_aborted(), "Aborting before root region scanning is finished not supported.");
 
-    _parallel_marking_threads = calc_parallel_marking_threads();
+    _parallel_marking_threads = MIN2(calc_parallel_marking_threads(),
+                                     // We distribute work on a per-region basis, so starting
+                                     // more threads than that is useless.
+                                     root_regions()->num_root_regions());
     assert(parallel_marking_threads() <= max_parallel_marking_threads(),
            "Maximum number of marking threads exceeded");
-    uint active_workers = MAX2(1U, parallel_marking_threads());
 
     G1CMRootRegionScanTask task(this);
-    _parallel_workers->set_active_workers(active_workers);
-    _parallel_workers->run_task(&task);
+    log_debug(gc, ergo)("Running %s using %u workers for %u work units.",
+                        task.name(), _parallel_marking_threads, root_regions()->num_root_regions());
+    _parallel_workers->run_task(&task, _parallel_marking_threads);
 
     // It's possible that has_aborted() is true here without actually
     // aborting the survivor scan earlier. This is OK as it's
--- a/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Tue May 10 21:38:44 2016 +0000
@@ -248,6 +248,9 @@
   // all have been claimed.
   HeapRegion* claim_next();
 
+  // The number of root regions to scan.
+  uint num_root_regions() const;
+
   void cancel_scan();
 
   // Flag that we're done with root region scanning and notify anyone
--- a/src/share/vm/gc/g1/heapRegionRemSet.cpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/gc/g1/heapRegionRemSet.cpp	Tue May 10 21:38:44 2016 +0000
@@ -103,7 +103,7 @@
       CardIdx_t from_card = (CardIdx_t)
           hw_offset >> (CardTableModRefBS::card_shift - LogHeapWordSize);
 
-      assert(0 <= from_card && (size_t)from_card < HeapRegion::CardsPerRegion,
+      assert((size_t)from_card < HeapRegion::CardsPerRegion,
              "Must be in range.");
       add_card_work(from_card, par);
     }
@@ -386,7 +386,7 @@
         uintptr_t(from_hr->bottom())
           >> CardTableModRefBS::card_shift;
       CardIdx_t card_index = from_card - from_hr_bot_card_index;
-      assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
+      assert((size_t)card_index < HeapRegion::CardsPerRegion,
              "Must be in range.");
       if (G1HRRSUseSparseTable &&
           _sparse_table.add_card(from_hrm_ind, card_index)) {
@@ -421,11 +421,9 @@
         // Transfer from sparse to fine-grain.
         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 < SparsePRTEntry::cards_num(); i++) {
+        for (int i = 0; i < sprt_entry->num_valid_cards(); i++) {
           CardIdx_t c = sprt_entry->card(i);
-          if (c != SparsePRTEntry::NullEntry) {
-            prt->add_card(c);
-          }
+          prt->add_card(c);
         }
         // Now we can delete the sparse entry.
         bool res = _sparse_table.delete_entry(from_hrm_ind);
@@ -680,7 +678,7 @@
       uintptr_t(hr->bottom()) >> CardTableModRefBS::card_shift;
     assert(from_card >= hr_bot_card_index, "Inv");
     CardIdx_t card_index = from_card - hr_bot_card_index;
-    assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
+    assert((size_t)card_index < HeapRegion::CardsPerRegion,
            "Must be in range.");
     return _sparse_table.contains_card(hr_ind, card_index);
   }
--- a/src/share/vm/gc/g1/sparsePRT.cpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/gc/g1/sparsePRT.cpp	Tue May 10 21:38:44 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "gc/g1/heapRegion.hpp"
+#include "gc/g1/heapRegionBounds.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
 #include "gc/g1/sparsePRT.hpp"
 #include "gc/shared/cardTableModRefBS.hpp"
@@ -32,57 +33,69 @@
 #include "runtime/atomic.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 
+// Check that the size of the SparsePRTEntry is evenly divisible by the maximum
+// member type to avoid SIGBUS when accessing them.
+STATIC_ASSERT(sizeof(SparsePRTEntry) % sizeof(int) == 0);
+
 void SparsePRTEntry::init(RegionIdx_t region_ind) {
+  // Check that the card array element type can represent all cards in the region.
+  // Choose a large SparsePRTEntry::card_elem_t (e.g. CardIdx_t) if required.
+  assert(((size_t)1 << (sizeof(SparsePRTEntry::card_elem_t) * BitsPerByte)) *
+         G1SATBCardTableModRefBS::card_size >= HeapRegionBounds::max_size(), "precondition");
+  assert(G1RSetSparseRegionEntries > 0, "precondition");
   _region_ind = region_ind;
-  _next_index = NullEntry;
-
-  for (int i = 0; i < cards_num(); i++) {
-    _cards[i] = NullEntry;
-  }
+  _next_index = RSHashTable::NullEntry;
+  _next_null = 0;
 }
 
 bool SparsePRTEntry::contains_card(CardIdx_t card_index) const {
-  for (int i = 0; i < cards_num(); i++) {
-    if (_cards[i] == card_index) return true;
+  for (int i = 0; i < num_valid_cards(); i++) {
+    if (card(i) == card_index) {
+      return true;
+    }
   }
   return false;
 }
 
-int SparsePRTEntry::num_valid_cards() const {
-  int sum = 0;
-  for (int i = 0; i < cards_num(); i++) {
-    sum += (_cards[i] != NullEntry);
+SparsePRTEntry::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 sum;
-}
-
-SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
-  for (int i = 0; i < cards_num(); i++) {
-    CardIdx_t c = _cards[i];
-    if (c == card_index) return found;
-    if (c == NullEntry) { _cards[i] = card_index; return added; }
-  }
+  if (num_valid_cards() < cards_num() - 1) {
+    _cards[_next_null] = (card_elem_t)card_index;
+    _next_null++;
+    return added;
+   }
   // Otherwise, we're full.
   return overflow;
 }
 
-void SparsePRTEntry::copy_cards(CardIdx_t* cards) const {
-  memcpy(cards, _cards, cards_num() * sizeof(CardIdx_t));
+void SparsePRTEntry::copy_cards(card_elem_t* cards) const {
+  memcpy(cards, _cards, cards_num() * sizeof(card_elem_t));
 }
 
 void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const {
-  copy_cards(&e->_cards[0]);
+  copy_cards(e->_cards);
+  assert(_next_null >= 0, "invariant");
+  assert(_next_null <= cards_num(), "invariant");
+  e->_next_null = _next_null;
 }
 
 // ----------------------------------------------------------------------
 
+float RSHashTable::TableOccupancyFactor = 0.5f;
+
 RSHashTable::RSHashTable(size_t capacity) :
   _capacity(capacity), _capacity_mask(capacity-1),
   _occupied_entries(0), _occupied_cards(0),
-  _entries((SparsePRTEntry*)NEW_C_HEAP_ARRAY(char, SparsePRTEntry::size() * capacity, mtGC)),
+  _entries(NULL),
   _buckets(NEW_C_HEAP_ARRAY(int, capacity, mtGC)),
   _free_list(NullEntry), _free_region(0)
 {
+  _num_entries = (capacity * TableOccupancyFactor) + 1;
+  _entries = (SparsePRTEntry*)NEW_C_HEAP_ARRAY(char, _num_entries * SparsePRTEntry::size(), mtGC);
   clear();
 }
 
@@ -107,7 +120,7 @@
                 "_capacity too large");
 
   // This will put -1 == NullEntry in the key field of all entries.
-  memset(_entries, NullEntry, _capacity * SparsePRTEntry::size());
+  memset(_entries, NullEntry, _num_entries * SparsePRTEntry::size());
   memset(_buckets, NullEntry, _capacity * sizeof(int));
   _free_list = NullEntry;
   _free_region = 0;
@@ -123,16 +136,6 @@
   return res != SparsePRTEntry::overflow;
 }
 
-bool RSHashTable::get_cards(RegionIdx_t region_ind, CardIdx_t* cards) {
-  SparsePRTEntry* entry = get_entry(region_ind);
-  if (entry == NULL) {
-    return false;
-  }
-  // Otherwise...
-  entry->copy_cards(cards);
-  return true;
-}
-
 SparsePRTEntry* RSHashTable::get_entry(RegionIdx_t region_ind) const {
   int ind = (int) (region_ind & capacity_mask());
   int cur_ind = _buckets[ind];
@@ -174,7 +177,6 @@
   SparsePRTEntry* res = get_entry(region_ind);
   if (res == NULL) {
     int new_ind = alloc_entry();
-    assert(0 <= new_ind && (size_t)new_ind < capacity(), "There should be room.");
     res = entry(new_ind);
     res->init(region_ind);
     // Insert at front.
@@ -192,7 +194,7 @@
     res = _free_list;
     _free_list = entry(res)->next_index();
     return res;
-  } else if ((size_t) _free_region+1 < capacity()) {
+  } else if ((size_t)_free_region < _num_entries) {
     res = _free_region;
     _free_region++;
     return res;
@@ -215,17 +217,16 @@
 }
 
 CardIdx_t RSHashTableIter::find_first_card_in_list() {
-  CardIdx_t res;
   while (_bl_ind != RSHashTable::NullEntry) {
-    res = _rsht->entry(_bl_ind)->card(0);
-    if (res != SparsePRTEntry::NullEntry) {
-      return res;
+    SparsePRTEntry* sparse_entry = _rsht->entry(_bl_ind);
+    if (sparse_entry->num_valid_cards() > 0) {
+      return sparse_entry->card(0);
     } else {
-      _bl_ind = _rsht->entry(_bl_ind)->next_index();
+      _bl_ind = sparse_entry->next_index();
     }
   }
   // Otherwise, none found:
-  return SparsePRTEntry::NullEntry;
+  return NoCardFound;
 }
 
 size_t RSHashTableIter::compute_card_ind(CardIdx_t ci) {
@@ -234,20 +235,22 @@
 
 bool RSHashTableIter::has_next(size_t& card_index) {
   _card_ind++;
-  CardIdx_t ci;
-  if (_card_ind < SparsePRTEntry::cards_num() &&
-      ((ci = _rsht->entry(_bl_ind)->card(_card_ind)) !=
-       SparsePRTEntry::NullEntry)) {
-    card_index = compute_card_ind(ci);
-    return true;
+  if (_bl_ind >= 0) {
+    SparsePRTEntry* e = _rsht->entry(_bl_ind);
+    if (_card_ind < e->num_valid_cards()) {
+      CardIdx_t ci = e->card(_card_ind);
+      card_index = compute_card_ind(ci);
+      return true;
+    }
   }
+
   // Otherwise, must find the next valid entry.
   _card_ind = 0;
 
   if (_bl_ind != RSHashTable::NullEntry) {
       _bl_ind = _rsht->entry(_bl_ind)->next_index();
-      ci = find_first_card_in_list();
-      if (ci != SparsePRTEntry::NullEntry) {
+      CardIdx_t ci = find_first_card_in_list();
+      if (ci != NoCardFound) {
         card_index = compute_card_ind(ci);
         return true;
       }
@@ -256,8 +259,8 @@
   _tbl_ind++;
   while ((size_t)_tbl_ind < _rsht->capacity()) {
     _bl_ind = _rsht->_buckets[_tbl_ind];
-    ci = find_first_card_in_list();
-    if (ci != SparsePRTEntry::NullEntry) {
+    CardIdx_t ci = find_first_card_in_list();
+    if (ci != NoCardFound) {
       card_index = compute_card_ind(ci);
       return true;
     }
@@ -275,7 +278,7 @@
 
 size_t RSHashTable::mem_size() const {
   return sizeof(RSHashTable) +
-    capacity() * (SparsePRTEntry::size() + sizeof(int));
+    _num_entries * (SparsePRTEntry::size() + sizeof(int));
 }
 
 // ----------------------------------------------------------------------
@@ -380,16 +383,12 @@
 }
 
 bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
-  if (_next->occupied_entries() * 2 > _next->capacity()) {
+  if (_next->should_expand()) {
     expand();
   }
   return _next->add_card(region_id, card_index);
 }
 
-bool SparsePRT::get_cards(RegionIdx_t region_id, CardIdx_t* cards) {
-  return _next->get_cards(region_id, cards);
-}
-
 SparsePRTEntry* SparsePRT::get_entry(RegionIdx_t region_id) {
   return _next->get_entry(region_id);
 }
@@ -427,7 +426,7 @@
 void SparsePRT::expand() {
   RSHashTable* last = _next;
   _next = new RSHashTable(last->capacity() * 2);
-  for (size_t i = 0; i < last->capacity(); i++) {
+  for (size_t i = 0; i < last->num_entries(); i++) {
     SparsePRTEntry* e = last->entry((int)i);
     if (e->valid_entry()) {
       _next->add_entry(e);
--- a/src/share/vm/gc/g1/sparsePRT.hpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/gc/g1/sparsePRT.hpp	Tue May 10 21:38:44 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,26 +43,32 @@
 // old versions synchronously.
 
 class SparsePRTEntry: public CHeapObj<mtGC> {
-public:
-  enum SomePublicConstants {
-    NullEntry     = -1,
-    UnrollFactor  =  4
-  };
 private:
+  // The type of a card entry.
+  typedef uint16_t card_elem_t;
+
+  // We need to make sizeof(SparsePRTEntry) an even multiple of maximum member size,
+  // in order to force correct alignment that could otherwise cause SIGBUS errors
+  // when reading the member variables. This calculates the minimum number of card
+  // array elements required to get that alignment.
+  static const size_t card_array_alignment = sizeof(int) / sizeof(card_elem_t);
+
   RegionIdx_t _region_ind;
   int         _next_index;
-  CardIdx_t   _cards[1];
+  int         _next_null;
+  // The actual cards stored in this array.
   // WARNING: Don't put any data members beyond this line. Card array has, in fact, variable length.
   // It should always be the last data member.
+  card_elem_t _cards[card_array_alignment];
+
+  // Copy the current entry's cards into "cards".
+  inline void copy_cards(card_elem_t* cards) const;
 public:
   // Returns the size of the entry, used for entry allocation.
-  static size_t size() { return sizeof(SparsePRTEntry) + sizeof(CardIdx_t) * (cards_num() - 1); }
+  static size_t size() { return sizeof(SparsePRTEntry) + sizeof(card_elem_t) * (cards_num() - card_array_alignment); }
   // Returns the size of the card array.
   static int cards_num() {
-    // The number of cards should be a multiple of 4, because that's our current
-    // unrolling factor.
-    static const int s = MAX2<int>(G1RSetSparseRegionEntries & ~(UnrollFactor - 1), UnrollFactor);
-    return s;
+    return align_size_up(G1RSetSparseRegionEntries, card_array_alignment);
   }
 
   // Set the region_ind to the given value, and delete all cards.
@@ -80,7 +86,7 @@
   inline bool contains_card(CardIdx_t card_index) const;
 
   // Returns the number of non-NULL card entries.
-  inline int num_valid_cards() const;
+  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
@@ -92,22 +98,25 @@
   };
   inline AddCardResult add_card(CardIdx_t card_index);
 
-  // Copy the current entry's cards into "cards".
-  inline void copy_cards(CardIdx_t* cards) const;
   // Copy the current entry's cards into the "_card" array of "e."
   inline void copy_cards(SparsePRTEntry* e) const;
 
-  inline CardIdx_t card(int i) const { return _cards[i]; }
+  inline CardIdx_t card(int i) const {
+    assert(i >= 0, "must be nonnegative");
+    assert(i < cards_num(), "range checking");
+    return (CardIdx_t)_cards[i];
+  }
 };
 
-
 class RSHashTable : public CHeapObj<mtGC> {
 
   friend class RSHashTableIter;
 
-  enum SomePrivateConstants {
-    NullEntry = -1
-  };
+
+  // Inverse maximum hash table occupancy used.
+  static float TableOccupancyFactor;
+
+  size_t _num_entries;
 
   size_t _capacity;
   size_t _capacity_mask;
@@ -136,6 +145,10 @@
   RSHashTable(size_t capacity);
   ~RSHashTable();
 
+  static const int NullEntry = -1;
+
+  bool should_expand() const { return _occupied_entries == _num_entries; }
+
   // 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".
@@ -156,27 +169,35 @@
 
   void clear();
 
-  size_t capacity() const      { return _capacity;       }
+  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 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; }
 
-  SparsePRTEntry* entry(int i) const { return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i); }
+  SparsePRTEntry* entry(int i) const {
+    assert(i >= 0 && (size_t)i < _num_entries, "precondition");
+    return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i);
+  }
 
   void print();
 };
 
 // ValueObj because will be embedded in HRRS iterator.
 class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
+  // Return value indicating "invalid/no card".
+  static const int NoCardFound = -1;
+
   int _tbl_ind;         // [-1, 0.._rsht->_capacity)
   int _bl_ind;          // [-1, 0.._rsht->_capacity)
   short _card_ind;      // [0..SparsePRTEntry::cards_num())
   RSHashTable* _rsht;
 
   // If the bucket list pointed to by _bl_ind contains a card, sets
-  // _bl_ind to the index of that entry, and returns the card.
-  // Otherwise, returns SparseEntry::NullEntry.
+  // _bl_ind to the index of that entry,
+  // Returns the card found if there is, otherwise returns InvalidCard.
   CardIdx_t find_first_card_in_list();
 
   // Computes the proper card index for the card whose offset in the
@@ -247,12 +268,6 @@
   // entries to a larger-capacity representation.
   bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
 
-  // If the table hold an entry for "region_ind",  Copies its
-  // cards into "cards", which must be an array of length at least
-  // "SparePRTEntry::cards_num()", and returns "true"; otherwise,
-  // returns "false".
-  bool get_cards(RegionIdx_t region_ind, CardIdx_t* cards);
-
   // Return the pointer to the entry associated with the given region.
   SparsePRTEntry* get_entry(RegionIdx_t region_ind);
 
--- a/src/share/vm/runtime/vmStructs.cpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/runtime/vmStructs.cpp	Tue May 10 21:38:44 2016 +0000
@@ -1365,6 +1365,12 @@
      static_field(java_lang_Class,             _oop_size_offset,                              int)                                   \
      static_field(java_lang_Class,             _static_oop_field_count_offset,                int)                                   \
                                                                                                                                      \
+  /******************/                                                                                                               \
+  /* VMError fields */                                                                                                               \
+  /******************/                                                                                                               \
+                                                                                                                                     \
+     static_field(VMError,                     _thread,                                       Thread*)                               \
+                                                                                                                                     \
   /************************/                                                                                                         \
   /* Miscellaneous fields */                                                                                                         \
   /************************/                                                                                                         \
@@ -2215,6 +2221,12 @@
                                                                           \
   declare_toplevel_type(Arguments)                                        \
                                                                           \
+  /***********/                                                           \
+  /* VMError */                                                           \
+  /***********/                                                           \
+                                                                          \
+  declare_toplevel_type(VMError)                                          \
+                                                                          \
   /***************/                                                       \
   /* Other types */                                                       \
   /***************/                                                       \
--- a/src/share/vm/utilities/vmError.hpp	Wed May 11 00:31:28 2016 +0300
+++ b/src/share/vm/utilities/vmError.hpp	Tue May 10 21:38:44 2016 +0000
@@ -33,6 +33,7 @@
 class VMError : public AllStatic {
   friend class VM_ReportJavaOutOfMemory;
   friend class Decoder;
+  friend class VMStructs;
 
   static int         _id;               // Solaris/Linux signals: 0 - SIGRTMAX
                                         // Windows exceptions: 0xCxxxxxxx system errors