changeset 57418:fe65e995a765

8234328: VectorSet::clear can cause fragmentation Reviewed-by: neliasso
author redestad
date Thu, 12 Dec 2019 14:22:50 +0100
parents c413a549dd57
children 2c724dba4c3c
files src/hotspot/share/libadt/vectset.cpp src/hotspot/share/libadt/vectset.hpp
diffstat 2 files changed, 23 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/libadt/vectset.cpp	Thu Dec 12 13:06:59 2019 +0000
+++ b/src/hotspot/share/libadt/vectset.cpp	Thu Dec 12 14:22:50 2019 +0100
@@ -31,17 +31,20 @@
 
 VectorSet::VectorSet(Arena *arena) : _size(2),
     _data(NEW_ARENA_ARRAY(arena, uint32_t, 2)),
+    _data_size(2),
     _set_arena(arena) {
   _data[0] = 0;
   _data[1] = 0;
 }
 
 // Expand the existing set to a bigger size
-void VectorSet::grow(uint new_size) {
-  new_size = (new_size + bit_mask) >> word_bits;
-  assert(new_size > 0, "sanity");
-  uint x = next_power_of_2(new_size);
-  _data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x);
+void VectorSet::grow(uint new_word_capacity) {
+  assert(new_word_capacity < (1U << 30), "");
+  uint x = next_power_of_2(new_word_capacity);
+  if (x > _data_size) {
+    _data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x);
+    _data_size = x;
+  }
   Copy::zero_to_bytes(_data + _size, (x - _size) * sizeof(uint32_t));
   _size = x;
 }
@@ -51,20 +54,11 @@
   uint32_t word = elem >> word_bits;
   uint32_t mask = 1U << (elem & bit_mask);
   if (word >= _size) {
-    grow(elem + 1);
+    grow(word);
   }
   _data[word] |= mask;
 }
 
-// Resets the storage
-void VectorSet::reset_memory() {
-  assert(_size >= 2, "_size can never be less than 2");
-  _data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, 2);
-  _size = 2;
-  _data[0] = 0;
-  _data[1] = 0;
-}
-
 // Return true if the set is empty
 bool VectorSet::is_empty() const {
   for (uint32_t i = 0; i < _size; i++) {
--- a/src/hotspot/share/libadt/vectset.hpp	Thu Dec 12 13:06:59 2019 +0000
+++ b/src/hotspot/share/libadt/vectset.hpp	Thu Dec 12 14:22:50 2019 +0100
@@ -40,12 +40,15 @@
   static const uint word_bits = 5;
   static const uint bit_mask  = 31;
 
-  uint       _size;             // Size of data in 32-bit words
-  uint32_t*  _data;             // The data, bit packed
+  // Used 32-bit words
+  uint       _size;
+  uint32_t*  _data;
+  // Allocated words
+  uint       _data_size;
   Arena*     _set_arena;
 
-  void grow(uint newsize);      // Grow vector to required bitsize
-  void reset_memory();
+  // Grow vector to required word capacity
+  void grow(uint new_word_capacity);
 public:
   VectorSet(Arena *arena);
   ~VectorSet() {}
@@ -53,15 +56,10 @@
   void insert(uint elem);
   bool is_empty() const;
   void reset() {
-    Copy::zero_to_bytes(_data, _size * sizeof(uint32_t));
+    _size = 0;
   }
   void clear() {
-    // Reclaim storage if huge
-    if (_size > 100) {
-      reset_memory();
-    } else {
-      reset();
-    }
+    reset();
   }
 
   // Fast inlined "test and set".  Replaces the idiom:
@@ -73,9 +71,8 @@
   bool test_set(uint elem) {
     uint32_t word = elem >> word_bits;
     if (word >= _size) {
-      // Then grow; set; return 0;
-      this->insert(elem);
-      return false;
+      // Then grow
+      grow(word);
     }
     uint32_t mask = 1U << (elem & bit_mask);
     uint32_t data = _data[word];
@@ -106,11 +103,10 @@
   void set(uint elem) {
     uint32_t word = elem >> word_bits;
     if (word >= _size) {
-      this->insert(elem);
-    } else {
-      uint32_t mask = 1U << (elem & bit_mask);
-      _data[word] |= mask;
+      grow(word);
     }
+    uint32_t mask = 1U << (elem & bit_mask);
+    _data[word] |= mask;
   }
 };