8055283: Expand ResourceHashtable with C_HEAP allocation, removal and some unit tests

Thu, 27 Feb 2020 06:41:35 +0000

author
andrew
date
Thu, 27 Feb 2020 06:41:35 +0000
changeset 9845
68172de2a0d7
parent 9844
6a809b1ac0a8
child 9846
9003f35baaa0

8055283: Expand ResourceHashtable with C_HEAP allocation, removal and some unit tests
Reviewed-by: phh

src/share/vm/prims/jni.cpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/resourceHash.cpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/resourceHash.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/prims/jni.cpp	Thu Feb 27 06:05:11 2020 +0000
     1.2 +++ b/src/share/vm/prims/jni.cpp	Thu Feb 27 06:41:35 2020 +0000
     1.3 @@ -5101,6 +5101,7 @@
     1.4  void TestNewSize_test();
     1.5  void TestKlass_test();
     1.6  void Test_linked_list();
     1.7 +void TestResourcehash_test();
     1.8  void TestChunkedList_test();
     1.9  #if INCLUDE_ALL_GCS
    1.10  void TestOldFreeSpaceCalculation_test();
    1.11 @@ -5133,6 +5134,7 @@
    1.12      run_unit_test(test_snprintf());
    1.13      run_unit_test(TestNewSize_test());
    1.14      run_unit_test(TestKlass_test());
    1.15 +    run_unit_test(TestResourcehash_test());
    1.16      run_unit_test(Test_linked_list());
    1.17      run_unit_test(TestChunkedList_test());
    1.18      run_unit_test(ObjectMonitor::sanity_checks());
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/share/vm/utilities/resourceHash.cpp	Thu Feb 27 06:41:35 2020 +0000
     2.3 @@ -0,0 +1,182 @@
     2.4 +/*
     2.5 + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + *
    2.26 + */
    2.27 +
    2.28 +#include "precompiled.hpp"
    2.29 +#include "memory/allocation.hpp"
    2.30 +#include "memory/resourceArea.hpp"
    2.31 +#include "utilities/debug.hpp"
    2.32 +#include "utilities/resourceHash.hpp"
    2.33 +
    2.34 +#ifndef PRODUCT
    2.35 +
    2.36 +/////////////// Unit tests ///////////////
    2.37 +
    2.38 +class TestResourceHashtable : public AllStatic {
    2.39 +  typedef void* K;
    2.40 +  typedef int V;
    2.41 +
    2.42 +  static unsigned identity_hash(const K& k) {
    2.43 +    return (unsigned)(uintptr_t)k;
    2.44 +  }
    2.45 +
    2.46 +  static unsigned bad_hash(const K& k) {
    2.47 +    return 1;
    2.48 +  }
    2.49 +
    2.50 +  class EqualityTestIter {
    2.51 +   public:
    2.52 +    bool do_entry(K const& k, V const& v) {
    2.53 +      assert((uintptr_t)k == (uintptr_t)v, "");
    2.54 +      return true; // continue iteration
    2.55 +    }
    2.56 +  };
    2.57 +
    2.58 +  template<
    2.59 +  unsigned (*HASH)  (K const&)           = primitive_hash<K>,
    2.60 +  bool     (*EQUALS)(K const&, K const&) = primitive_equals<K>,
    2.61 +  unsigned SIZE = 256,
    2.62 +  ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
    2.63 +  MEMFLAGS MEM_TYPE = mtInternal
    2.64 +  >
    2.65 +  class Runner : public AllStatic {
    2.66 +    static void* as_K(uintptr_t val) { return (void*)val; }
    2.67 +
    2.68 +   public:
    2.69 +    static void test_small() {
    2.70 +      EqualityTestIter et;
    2.71 +      ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
    2.72 +
    2.73 +      assert(!rh.contains(as_K(0x1)), "");
    2.74 +
    2.75 +      assert(rh.put(as_K(0x1), 0x1), "");
    2.76 +      assert(rh.contains(as_K(0x1)), "");
    2.77 +
    2.78 +      assert(!rh.put(as_K(0x1), 0x1), "");
    2.79 +
    2.80 +      assert(rh.put(as_K(0x2), 0x2), "");
    2.81 +      assert(rh.put(as_K(0x3), 0x3), "");
    2.82 +      assert(rh.put(as_K(0x4), 0x4), "");
    2.83 +      assert(rh.put(as_K(0x5), 0x5), "");
    2.84 +
    2.85 +      assert(!rh.remove(as_K(0x0)), "");
    2.86 +      rh.iterate(&et);
    2.87 +
    2.88 +      assert(rh.remove(as_K(0x1)), "");
    2.89 +      rh.iterate(&et);
    2.90 +
    2.91 +    }
    2.92 +
    2.93 +    // We use keys with the low bits cleared since the default hash will do some shifting
    2.94 +    static void test_small_shifted() {
    2.95 +      EqualityTestIter et;
    2.96 +      ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
    2.97 +
    2.98 +      assert(!rh.contains(as_K(0x10)), "");
    2.99 +
   2.100 +      assert(rh.put(as_K(0x10), 0x10), "");
   2.101 +      assert(rh.contains(as_K(0x10)), "");
   2.102 +
   2.103 +      assert(!rh.put(as_K(0x10), 0x10), "");
   2.104 +
   2.105 +      assert(rh.put(as_K(0x20), 0x20), "");
   2.106 +      assert(rh.put(as_K(0x30), 0x30), "");
   2.107 +      assert(rh.put(as_K(0x40), 0x40), "");
   2.108 +      assert(rh.put(as_K(0x50), 0x50), "");
   2.109 +
   2.110 +      assert(!rh.remove(as_K(0x00)), "");
   2.111 +
   2.112 +      assert(rh.remove(as_K(0x10)), "");
   2.113 +
   2.114 +      rh.iterate(&et);
   2.115 +    }
   2.116 +
   2.117 +    static void test(unsigned num_elements = SIZE) {
   2.118 +      EqualityTestIter et;
   2.119 +      ResourceHashtable<K, V, HASH, EQUALS, SIZE, ALLOC_TYPE, MEM_TYPE> rh;
   2.120 +
   2.121 +      for (uintptr_t i = 0; i < num_elements; ++i) {
   2.122 +        assert(rh.put(as_K(i), i), "");
   2.123 +      }
   2.124 +
   2.125 +      rh.iterate(&et);
   2.126 +
   2.127 +      for (uintptr_t i = num_elements; i > 0; --i) {
   2.128 +        uintptr_t index = i - 1;
   2.129 +        assert(rh.remove(as_K(index)), "");
   2.130 +      }
   2.131 +      rh.iterate(&et);
   2.132 +      for (uintptr_t i = num_elements; i > 0; --i) {
   2.133 +        uintptr_t index = i - 1;
   2.134 +        assert(!rh.remove(as_K(index)), "");
   2.135 +      }
   2.136 +      rh.iterate(&et);
   2.137 +    }
   2.138 +  };
   2.139 +
   2.140 + public:
   2.141 +  static void run_tests() {
   2.142 +    {
   2.143 +      ResourceMark rm;
   2.144 +      Runner<>::test_small();
   2.145 +      Runner<>::test_small_shifted();
   2.146 +      Runner<>::test();
   2.147 +    }
   2.148 +
   2.149 +    {
   2.150 +      ResourceMark rm;
   2.151 +      Runner<identity_hash>::test_small();
   2.152 +      Runner<identity_hash>::test_small_shifted();
   2.153 +      Runner<identity_hash>::test();
   2.154 +    }
   2.155 +
   2.156 +    {
   2.157 +      ResourceMark rm;
   2.158 +      Runner<bad_hash>::test_small();
   2.159 +      Runner<bad_hash>::test_small_shifted();
   2.160 +      Runner<bad_hash>::test();
   2.161 +    }
   2.162 +
   2.163 +
   2.164 +    assert(Thread::current()->resource_area()->nesting() == 0, "this code depends on not having an active ResourceMark");
   2.165 +    // The following test calls will cause an assert if resource allocations occur since we don't have an active mark
   2.166 +    Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
   2.167 +    Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
   2.168 +    Runner<primitive_hash<K>, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
   2.169 +
   2.170 +    Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small();
   2.171 +    Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test_small_shifted();
   2.172 +    Runner<bad_hash, primitive_equals<K>, 512, ResourceObj::C_HEAP>::test();
   2.173 +
   2.174 +    Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small();
   2.175 +    Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test_small_shifted();
   2.176 +    Runner<identity_hash, primitive_equals<K>, 1, ResourceObj::C_HEAP>::test(512);
   2.177 +  }
   2.178 +};
   2.179 +
   2.180 +void TestResourcehash_test() {
   2.181 +  TestResourceHashtable::run_tests();
   2.182 +}
   2.183 +
   2.184 +#endif // not PRODUCT
   2.185 +
     3.1 --- a/src/share/vm/utilities/resourceHash.hpp	Thu Feb 27 06:05:11 2020 +0000
     3.2 +++ b/src/share/vm/utilities/resourceHash.hpp	Thu Feb 27 06:41:35 2020 +0000
     3.3 @@ -1,5 +1,5 @@
     3.4  /*
     3.5 - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     3.6 + * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
     3.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.8   *
     3.9   * This code is free software; you can redistribute it and/or modify it
    3.10 @@ -35,7 +35,7 @@
    3.11  
    3.12  template<typename K> unsigned primitive_hash(const K& k) {
    3.13    unsigned hash = (unsigned)((uintptr_t)k);
    3.14 -  return hash ^ (hash > 3); // just in case we're dealing with aligned ptrs
    3.15 +  return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs
    3.16  }
    3.17  
    3.18  template<typename K> bool primitive_equals(const K& k0, const K& k1) {
    3.19 @@ -50,7 +50,9 @@
    3.20      //typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>,
    3.21      unsigned (*HASH)  (K const&)           = primitive_hash<K>,
    3.22      bool     (*EQUALS)(K const&, K const&) = primitive_equals<K>,
    3.23 -    unsigned SIZE = 256
    3.24 +    unsigned SIZE = 256,
    3.25 +    ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
    3.26 +    MEMFLAGS MEM_TYPE = mtInternal
    3.27      >
    3.28  class ResourceHashtable : public ResourceObj {
    3.29   private:
    3.30 @@ -91,6 +93,21 @@
    3.31   public:
    3.32    ResourceHashtable() { memset(_table, 0, SIZE * sizeof(Node*)); }
    3.33  
    3.34 +  ~ResourceHashtable() {
    3.35 +    if (ALLOC_TYPE == C_HEAP) {
    3.36 +      Node* const* bucket = _table;
    3.37 +      while (bucket < &_table[SIZE]) {
    3.38 +        Node* node = *bucket;
    3.39 +        while (node != NULL) {
    3.40 +          Node* cur = node;
    3.41 +          node = node->_next;
    3.42 +          delete cur;
    3.43 +        }
    3.44 +        ++bucket;
    3.45 +      }
    3.46 +    }
    3.47 +  }
    3.48 +
    3.49    bool contains(K const& key) const {
    3.50      return get(key) != NULL;
    3.51    }
    3.52 @@ -105,17 +122,38 @@
    3.53      }
    3.54    }
    3.55  
    3.56 -  // Inserts or replaces a value in the table
    3.57 -  void put(K const& key, V const& value) {
    3.58 + /**
    3.59 +  * Inserts or replaces a value in the table.
    3.60 +  * @return: true:  if a new item is added
    3.61 +  *          false: if the item already existed and the value is updated
    3.62 +  */
    3.63 +  bool put(K const& key, V const& value) {
    3.64      unsigned hv = HASH(key);
    3.65      Node** ptr = lookup_node(hv, key);
    3.66      if (*ptr != NULL) {
    3.67        (*ptr)->_value = value;
    3.68 +      return false;
    3.69      } else {
    3.70 -      *ptr = new Node(hv, key, value);
    3.71 +      *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value);
    3.72 +      return true;
    3.73      }
    3.74    }
    3.75  
    3.76 +  bool remove(K const& key) {
    3.77 +    unsigned hv = HASH(key);
    3.78 +    Node** ptr = lookup_node(hv, key);
    3.79 +
    3.80 +    Node* node = *ptr;
    3.81 +    if (node != NULL) {
    3.82 +      *ptr = node->_next;
    3.83 +      if (ALLOC_TYPE == C_HEAP) {
    3.84 +        delete node;
    3.85 +      }
    3.86 +      return true;
    3.87 +    }
    3.88 +    return false;
    3.89 +  }
    3.90 +
    3.91    // ITER contains bool do_entry(K const&, V const&), which will be
    3.92    // called for each entry in the table.  If do_entry() returns false,
    3.93    // the iteration is cancelled.
    3.94 @@ -132,6 +170,10 @@
    3.95        ++bucket;
    3.96      }
    3.97    }
    3.98 +
    3.99 +  static size_t node_size() {
   3.100 +    return sizeof(Node);
   3.101 +  }
   3.102  };
   3.103  
   3.104  

mercurial