1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_UTILITIES_RESOURCEHASH_HPP 26 #define SHARE_VM_UTILITIES_RESOURCEHASH_HPP 27 28 #include "memory/allocation.hpp" 29 30 template<typename K> struct ResourceHashtableFns { 31 typedef unsigned (*hash_fn)(K const&); 32 typedef bool (*equals_fn)(K const&, K const&); 33 }; 34 35 template<typename K> unsigned primitive_hash(const K& k) { 36 unsigned hash = (unsigned)((uintptr_t)k); 37 return hash ^ (hash >> 3); // just in case we're dealing with aligned ptrs 38 } 39 40 template<typename K> bool primitive_equals(const K& k0, const K& k1) { 41 return k0 == k1; 42 } 43 44 enum { 45 CONFIGURABLE_SIZE = 0 46 }; 47 48 template< 49 typename K, typename V, 50 // xlC does not compile this: 51 // http://stackoverflow.com/questions/8532961/template-argument-of-type-that-is-defined-by-inner-typedef-from-other-template-c 52 //typename ResourceHashtableFns<K>::hash_fn HASH = primitive_hash<K>, 53 //typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>, 54 unsigned (*HASH) (K const&) = primitive_hash<K>, 55 bool (*EQUALS)(K const&, K const&) = primitive_equals<K>, 56 unsigned SIZE = 256, 57 ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA, 58 MEMFLAGS MEM_TYPE = mtInternal 59 > 60 class ResourceHashtable : public ResourceObj { 61 private: 62 63 class Node : public ResourceObj { 64 public: 65 unsigned _hash; 66 K _key; 67 V _value; 68 Node* _next; 69 70 Node(unsigned hash, K const& key, V const& value) : 71 _hash(hash), _key(key), _value(value), _next(NULL) {} 72 }; 73 74 Node* _static_table[SIZE == 0 ? 1 : SIZE]; 75 unsigned _configured_table_size; 76 Node** _configured_table; 77 78 // Returns a pointer to where the node where the value would reside if 79 // it's in the table. 80 Node** lookup_node(unsigned hash, K const& key) { 81 unsigned index = hash % size(); 82 Node** table = get_table(); 83 Node** ptr = &table[index]; 84 while (*ptr != NULL) { 85 Node* node = *ptr; 86 if (node->_hash == hash && EQUALS(key, node->_key)) { 87 break; 88 } 89 ptr = &(node->_next); 90 } 91 return ptr; 92 } 93 94 Node const** lookup_node(unsigned hash, K const& key) const { 95 return const_cast<Node const**>( 96 const_cast<ResourceHashtable*>(this)->lookup_node(hash, key)); 97 } 98 99 public: 100 ResourceHashtable() { 101 assert(SIZE != CONFIGURABLE_SIZE, "must be"); 102 memset(_static_table, 0, SIZE * sizeof(Node*)); 103 _configured_table = NULL; 104 } 105 106 ResourceHashtable(unsigned configured_table_size) : _configured_table_size(configured_table_size) { 107 assert(SIZE == CONFIGURABLE_SIZE, "must be"); 108 _configured_table = (Node**)operator new(size() * sizeof(Node*), ALLOC_TYPE, MEM_TYPE); 109 memset(_configured_table, 0, size() * sizeof(Node*)); 110 } 111 112 ALWAYSINLINE unsigned size() const { 113 if (SIZE != CONFIGURABLE_SIZE) { 114 return SIZE; 115 } else { 116 return _configured_table_size; 117 } 118 } 119 120 ALWAYSINLINE Node** get_table() const { 121 if (SIZE != CONFIGURABLE_SIZE) { 122 return (Node**)(&_static_table[0]); 123 } else { 124 return _configured_table; 125 } 126 } 127 128 ~ResourceHashtable() { 129 if (ALLOC_TYPE == C_HEAP) { 130 Node** table = get_table(); 131 Node* const* bucket = table; 132 while (bucket < &table[size()]) { 133 Node* node = *bucket; 134 while (node != NULL) { 135 Node* cur = node; 136 node = node->_next; 137 delete cur; 138 } 139 ++bucket; 140 } 141 if (_configured_table != NULL) { 142 FreeHeap((void*)_configured_table); 143 } 144 } 145 } 146 147 bool contains(K const& key) const { 148 return get(key) != NULL; 149 } 150 151 V* get(K const& key) const { 152 unsigned hv = HASH(key); 153 Node const** ptr = lookup_node(hv, key); 154 if (*ptr != NULL) { 155 return const_cast<V*>(&(*ptr)->_value); 156 } else { 157 return NULL; 158 } 159 } 160 161 /** 162 * Inserts or replaces a value in the table. 163 * @return: true: if a new item is added 164 * false: if the item already existed and the value is updated 165 */ 166 bool put(K const& key, V const& value) { 167 unsigned hv = HASH(key); 168 Node** ptr = lookup_node(hv, key); 169 if (*ptr != NULL) { 170 (*ptr)->_value = value; 171 return false; 172 } else { 173 *ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value); 174 return true; 175 } 176 } 177 178 bool remove(K const& key) { 179 unsigned hv = HASH(key); 180 Node** ptr = lookup_node(hv, key); 181 182 Node* node = *ptr; 183 if (node != NULL) { 184 *ptr = node->_next; 185 if (ALLOC_TYPE == C_HEAP) { 186 delete node; 187 } 188 return true; 189 } 190 return false; 191 } 192 193 // ITER contains bool do_entry(K const&, V const&), which will be 194 // called for each entry in the table. If do_entry() returns false, 195 // the iteration is cancelled. 196 template<class ITER> 197 void iterate(ITER* iter) const { 198 Node** table = get_table(); 199 Node* const* bucket = table; 200 while (bucket < &table[size()]) { 201 Node* node = *bucket; 202 while (node != NULL) { 203 bool cont = iter->do_entry(node->_key, node->_value); 204 if (!cont) { return; } 205 node = node->_next; 206 } 207 ++bucket; 208 } 209 } 210 211 static size_t node_size() { 212 return sizeof(Node); 213 } 214 }; 215 216 217 #endif // SHARE_VM_UTILITIES_RESOURCEHASH_HPP