src/share/vm/utilities/linkedlist.hpp

Wed, 27 Aug 2014 08:19:12 -0400

author
zgu
date
Wed, 27 Aug 2014 08:19:12 -0400
changeset 7074
833b0f92429a
permissions
-rw-r--r--

8046598: Scalable Native memory tracking development
Summary: Enhance scalability of native memory tracking
Reviewed-by: coleenp, ctornqvi, gtriantafill

zgu@7074 1 /*
zgu@7074 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
zgu@7074 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
zgu@7074 4 *
zgu@7074 5 * This code is free software; you can redistribute it and/or modify it
zgu@7074 6 * under the terms of the GNU General Public License version 2 only, as
zgu@7074 7 * published by the Free Software Foundation.
zgu@7074 8 *
zgu@7074 9 * This code is distributed in the hope that it will be useful, but WITHOUT
zgu@7074 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
zgu@7074 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
zgu@7074 12 * version 2 for more details (a copy is included in the LICENSE file that
zgu@7074 13 * accompanied this code).
zgu@7074 14 *
zgu@7074 15 * You should have received a copy of the GNU General Public License version
zgu@7074 16 * 2 along with this work; if not, write to the Free Software Foundation,
zgu@7074 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
zgu@7074 18 *
zgu@7074 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
zgu@7074 20 * or visit www.oracle.com if you need additional information or have any
zgu@7074 21 * questions.
zgu@7074 22 *
zgu@7074 23 */
zgu@7074 24
zgu@7074 25 #ifndef SHARE_VM_UTILITIES_LINKED_LIST_HPP
zgu@7074 26 #define SHARE_VM_UTILITIES_LINKED_LIST_HPP
zgu@7074 27
zgu@7074 28 #include "memory/allocation.hpp"
zgu@7074 29
zgu@7074 30 /*
zgu@7074 31 * The implementation of a generic linked list, which uses various
zgu@7074 32 * backing storages, such as C heap, arena and resource, etc.
zgu@7074 33 */
zgu@7074 34
zgu@7074 35
zgu@7074 36 // An entry in a linked list. It should use the same backing storage
zgu@7074 37 // as the linked list that contains this entry.
zgu@7074 38 template <class E> class LinkedListNode : public ResourceObj {
zgu@7074 39 private:
zgu@7074 40 E _data; // embedded content
zgu@7074 41 LinkedListNode<E>* _next; // next entry
zgu@7074 42
zgu@7074 43 protected:
zgu@7074 44 LinkedListNode() : _next(NULL) { }
zgu@7074 45
zgu@7074 46 public:
zgu@7074 47 LinkedListNode(const E& e): _data(e), _next(NULL) { }
zgu@7074 48
zgu@7074 49 inline void set_next(LinkedListNode<E>* node) { _next = node; }
zgu@7074 50 inline LinkedListNode<E> * next() const { return _next; }
zgu@7074 51
zgu@7074 52 E* data() { return &_data; }
zgu@7074 53 const E* peek() const { return &_data; }
zgu@7074 54 };
zgu@7074 55
zgu@7074 56 // A linked list interface. It does not specify
zgu@7074 57 // any storage type it uses, so all methods involving
zgu@7074 58 // memory allocation or deallocation are pure virtual
zgu@7074 59 template <class E> class LinkedList : public ResourceObj {
zgu@7074 60 protected:
zgu@7074 61 LinkedListNode<E>* _head;
zgu@7074 62
zgu@7074 63 public:
zgu@7074 64 LinkedList() : _head(NULL) { }
zgu@7074 65
zgu@7074 66 inline void set_head(LinkedListNode<E>* h) { _head = h; }
zgu@7074 67 inline LinkedListNode<E>* head() const { return _head; }
zgu@7074 68 inline bool is_empty() const { return head() == NULL; }
zgu@7074 69
zgu@7074 70 inline size_t size() const {
zgu@7074 71 LinkedListNode<E>* p;
zgu@7074 72 size_t count = 0;
zgu@7074 73 for (p = head(); p != NULL; count++, p = p->next());
zgu@7074 74 return count;
zgu@7074 75 }
zgu@7074 76
zgu@7074 77 // Move all entries from specified linked list to this one
zgu@7074 78 virtual void move(LinkedList<E>* list) = 0;
zgu@7074 79
zgu@7074 80 // Add an entry to this linked list
zgu@7074 81 virtual LinkedListNode<E>* add(const E& e) = 0;
zgu@7074 82 // Add all entries from specified linked list to this one,
zgu@7074 83 virtual void add(LinkedListNode<E>* node) = 0;
zgu@7074 84
zgu@7074 85 // Add a linked list to this linked list
zgu@7074 86 virtual bool add(const LinkedList<E>* list) = 0;
zgu@7074 87
zgu@7074 88 // Search entry in the linked list
zgu@7074 89 virtual LinkedListNode<E>* find_node(const E& e) = 0;
zgu@7074 90 virtual E* find(const E& e) = 0;
zgu@7074 91
zgu@7074 92 // Insert entry to the linked list
zgu@7074 93 virtual LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref) = 0;
zgu@7074 94 virtual LinkedListNode<E>* insert_after (const E& e, LinkedListNode<E>* ref) = 0;
zgu@7074 95
zgu@7074 96 // Remove entry from the linked list
zgu@7074 97 virtual bool remove(const E& e) = 0;
zgu@7074 98 virtual bool remove(LinkedListNode<E>* node) = 0;
zgu@7074 99 virtual bool remove_before(LinkedListNode<E>* ref) = 0;
zgu@7074 100 virtual bool remove_after(LinkedListNode<E>* ref) = 0;
zgu@7074 101
zgu@7074 102 LinkedListNode<E>* unlink_head() {
zgu@7074 103 LinkedListNode<E>* h = this->head();
zgu@7074 104 if (h != NULL) {
zgu@7074 105 this->set_head(h->next());
zgu@7074 106 }
zgu@7074 107 return h;
zgu@7074 108 }
zgu@7074 109
zgu@7074 110 DEBUG_ONLY(virtual ResourceObj::allocation_type storage_type() = 0;)
zgu@7074 111 };
zgu@7074 112
zgu@7074 113 // A linked list implementation.
zgu@7074 114 // The linked list can be allocated in various type of memory: C heap, arena and resource area, etc.
zgu@7074 115 template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP,
zgu@7074 116 MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL>
zgu@7074 117 class LinkedListImpl : public LinkedList<E> {
zgu@7074 118 protected:
zgu@7074 119 Arena* _arena;
zgu@7074 120 public:
zgu@7074 121 LinkedListImpl() : _arena(NULL) { }
zgu@7074 122 LinkedListImpl(Arena* a) : _arena(a) { }
zgu@7074 123
zgu@7074 124 virtual ~LinkedListImpl() {
zgu@7074 125 clear();
zgu@7074 126 }
zgu@7074 127
zgu@7074 128 virtual void clear() {
zgu@7074 129 LinkedListNode<E>* p = this->head();
zgu@7074 130 this->set_head(NULL);
zgu@7074 131 while (p != NULL) {
zgu@7074 132 LinkedListNode<E>* to_delete = p;
zgu@7074 133 p = p->next();
zgu@7074 134 delete_node(to_delete);
zgu@7074 135 }
zgu@7074 136 }
zgu@7074 137
zgu@7074 138 // Add an entry to the linked list
zgu@7074 139 virtual LinkedListNode<E>* add(const E& e) {
zgu@7074 140 LinkedListNode<E>* node = this->new_node(e);
zgu@7074 141 if (node != NULL) {
zgu@7074 142 this->add(node);
zgu@7074 143 }
zgu@7074 144
zgu@7074 145 return node;
zgu@7074 146 }
zgu@7074 147
zgu@7074 148 virtual void add(LinkedListNode<E>* node) {
zgu@7074 149 assert(node != NULL, "NULL pointer");
zgu@7074 150 node->set_next(this->head());
zgu@7074 151 this->set_head(node);
zgu@7074 152 }
zgu@7074 153
zgu@7074 154 // Move a linked list to this linked list, both have to be allocated on the same
zgu@7074 155 // storage type.
zgu@7074 156 virtual void move(LinkedList<E>* list) {
zgu@7074 157 assert(list->storage_type() == this->storage_type(), "Different storage type");
zgu@7074 158 LinkedListNode<E>* node = this->head();
zgu@7074 159 while (node != NULL && node->next() != NULL) {
zgu@7074 160 node = node->next();
zgu@7074 161 }
zgu@7074 162 if (node == NULL) {
zgu@7074 163 this->set_head(list->head());
zgu@7074 164 } else {
zgu@7074 165 node->set_next(list->head());
zgu@7074 166 }
zgu@7074 167 // All entries are moved
zgu@7074 168 list->set_head(NULL);
zgu@7074 169 }
zgu@7074 170
zgu@7074 171 virtual bool add(const LinkedList<E>* list) {
zgu@7074 172 LinkedListNode<E>* node = list->head();
zgu@7074 173 while (node != NULL) {
zgu@7074 174 if (this->add(*node->peek()) == NULL) {
zgu@7074 175 return false;
zgu@7074 176 }
zgu@7074 177 node = node->next();
zgu@7074 178 }
zgu@7074 179 return true;
zgu@7074 180 }
zgu@7074 181
zgu@7074 182
zgu@7074 183 virtual LinkedListNode<E>* find_node(const E& e) {
zgu@7074 184 LinkedListNode<E>* p = this->head();
zgu@7074 185 while (p != NULL && !p->peek()->equals(e)) {
zgu@7074 186 p = p->next();
zgu@7074 187 }
zgu@7074 188 return p;
zgu@7074 189 }
zgu@7074 190
zgu@7074 191 E* find(const E& e) {
zgu@7074 192 LinkedListNode<E>* node = find_node(e);
zgu@7074 193 return (node == NULL) ? NULL : node->data();
zgu@7074 194 }
zgu@7074 195
zgu@7074 196
zgu@7074 197 // Add an entry in front of the reference entry
zgu@7074 198 LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref_node) {
zgu@7074 199 LinkedListNode<E>* node = this->new_node(e);
zgu@7074 200 if (node == NULL) return NULL;
zgu@7074 201 if (ref_node == this->head()) {
zgu@7074 202 node->set_next(ref_node);
zgu@7074 203 this->set_head(node);
zgu@7074 204 } else {
zgu@7074 205 LinkedListNode<E>* p = this->head();
zgu@7074 206 while (p != NULL && p->next() != ref_node) {
zgu@7074 207 p = p->next();
zgu@7074 208 }
zgu@7074 209 assert(p != NULL, "ref_node not in the list");
zgu@7074 210 node->set_next(ref_node);
zgu@7074 211 p->set_next(node);
zgu@7074 212 }
zgu@7074 213 return node;
zgu@7074 214 }
zgu@7074 215
zgu@7074 216 // Add an entry behind the reference entry
zgu@7074 217 LinkedListNode<E>* insert_after(const E& e, LinkedListNode<E>* ref_node) {
zgu@7074 218 LinkedListNode<E>* node = this->new_node(e);
zgu@7074 219 if (node == NULL) return NULL;
zgu@7074 220 node->set_next(ref_node->next());
zgu@7074 221 ref_node->set_next(node);
zgu@7074 222 return node;
zgu@7074 223 }
zgu@7074 224
zgu@7074 225 // Remove an entry from the linked list.
zgu@7074 226 // Return true if the entry is successfully removed
zgu@7074 227 virtual bool remove(const E& e) {
zgu@7074 228 LinkedListNode<E>* tmp = this->head();
zgu@7074 229 LinkedListNode<E>* prev = NULL;
zgu@7074 230
zgu@7074 231 while (tmp != NULL) {
zgu@7074 232 if (tmp->peek()->equals(e)) {
zgu@7074 233 return remove_after(prev);
zgu@7074 234 }
zgu@7074 235 prev = tmp;
zgu@7074 236 tmp = tmp->next();
zgu@7074 237 }
zgu@7074 238 return false;
zgu@7074 239 }
zgu@7074 240
zgu@7074 241 // Remove the node after the reference entry
zgu@7074 242 virtual bool remove_after(LinkedListNode<E>* prev) {
zgu@7074 243 LinkedListNode<E>* to_delete;
zgu@7074 244 if (prev == NULL) {
zgu@7074 245 to_delete = this->unlink_head();
zgu@7074 246 } else {
zgu@7074 247 to_delete = prev->next();
zgu@7074 248 if (to_delete != NULL) {
zgu@7074 249 prev->set_next(to_delete->next());
zgu@7074 250 }
zgu@7074 251 }
zgu@7074 252
zgu@7074 253 if (to_delete != NULL) {
zgu@7074 254 delete_node(to_delete);
zgu@7074 255 return true;
zgu@7074 256 }
zgu@7074 257 return false;
zgu@7074 258 }
zgu@7074 259
zgu@7074 260 virtual bool remove(LinkedListNode<E>* node) {
zgu@7074 261 LinkedListNode<E>* p = this->head();
zgu@7074 262 while (p != NULL && p->next() != node) {
zgu@7074 263 p = p->next();
zgu@7074 264 }
zgu@7074 265 if (p != NULL) {
zgu@7074 266 p->set_next(node->next());
zgu@7074 267 delete_node(node);
zgu@7074 268 return true;
zgu@7074 269 } else {
zgu@7074 270 return false;
zgu@7074 271 }
zgu@7074 272 }
zgu@7074 273
zgu@7074 274 virtual bool remove_before(LinkedListNode<E>* ref) {
zgu@7074 275 assert(ref != NULL, "NULL pointer");
zgu@7074 276 LinkedListNode<E>* p = this->head();
zgu@7074 277 LinkedListNode<E>* to_delete = NULL; // to be deleted
zgu@7074 278 LinkedListNode<E>* prev = NULL; // node before the node to be deleted
zgu@7074 279 while (p != NULL && p != ref) {
zgu@7074 280 prev = to_delete;
zgu@7074 281 to_delete = p;
zgu@7074 282 p = p->next();
zgu@7074 283 }
zgu@7074 284 if (p == NULL || to_delete == NULL) return false;
zgu@7074 285 assert(to_delete->next() == ref, "Wrong node to delete");
zgu@7074 286 assert(prev == NULL || prev->next() == to_delete,
zgu@7074 287 "Sanity check");
zgu@7074 288 if (prev == NULL) {
zgu@7074 289 assert(to_delete == this->head(), "Must be head");
zgu@7074 290 this->set_head(to_delete->next());
zgu@7074 291 } else {
zgu@7074 292 prev->set_next(to_delete->next());
zgu@7074 293 }
zgu@7074 294 delete_node(to_delete);
zgu@7074 295 return true;
zgu@7074 296 }
zgu@7074 297
zgu@7074 298 DEBUG_ONLY(ResourceObj::allocation_type storage_type() { return T; })
zgu@7074 299 protected:
zgu@7074 300 // Create new linked list node object in specified storage
zgu@7074 301 LinkedListNode<E>* new_node(const E& e) const {
zgu@7074 302 switch(T) {
zgu@7074 303 case ResourceObj::ARENA: {
zgu@7074 304 assert(_arena != NULL, "Arena not set");
zgu@7074 305 return new(_arena) LinkedListNode<E>(e);
zgu@7074 306 }
zgu@7074 307 case ResourceObj::RESOURCE_AREA:
zgu@7074 308 case ResourceObj::C_HEAP: {
zgu@7074 309 if (alloc_failmode == AllocFailStrategy::RETURN_NULL) {
zgu@7074 310 return new(std::nothrow, T, F) LinkedListNode<E>(e);
zgu@7074 311 } else {
zgu@7074 312 return new(T, F) LinkedListNode<E>(e);
zgu@7074 313 }
zgu@7074 314 }
zgu@7074 315 default:
zgu@7074 316 ShouldNotReachHere();
zgu@7074 317 }
zgu@7074 318 return NULL;
zgu@7074 319 }
zgu@7074 320
zgu@7074 321 // Delete linked list node object
zgu@7074 322 void delete_node(LinkedListNode<E>* node) {
zgu@7074 323 if (T == ResourceObj::C_HEAP) {
zgu@7074 324 delete node;
zgu@7074 325 }
zgu@7074 326 }
zgu@7074 327 };
zgu@7074 328
zgu@7074 329 // Sorted linked list. The linked list maintains sorting order specified by the comparison
zgu@7074 330 // function
zgu@7074 331 template <class E, int (*FUNC)(const E&, const E&),
zgu@7074 332 ResourceObj::allocation_type T = ResourceObj::C_HEAP,
zgu@7074 333 MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL>
zgu@7074 334 class SortedLinkedList : public LinkedListImpl<E, T, F, alloc_failmode> {
zgu@7074 335 public:
zgu@7074 336 SortedLinkedList() { }
zgu@7074 337 SortedLinkedList(Arena* a) : LinkedListImpl<E, T, F, alloc_failmode>(a) { }
zgu@7074 338
zgu@7074 339 virtual LinkedListNode<E>* add(const E& e) {
zgu@7074 340 return LinkedListImpl<E, T, F, alloc_failmode>::add(e);
zgu@7074 341 }
zgu@7074 342
zgu@7074 343 virtual void move(LinkedList<E>* list) {
zgu@7074 344 assert(list->storage_type() == this->storage_type(), "Different storage type");
zgu@7074 345 LinkedListNode<E>* node;
zgu@7074 346 while ((node = list->unlink_head()) != NULL) {
zgu@7074 347 this->add(node);
zgu@7074 348 }
zgu@7074 349 assert(list->is_empty(), "All entries are moved");
zgu@7074 350 }
zgu@7074 351
zgu@7074 352 virtual void add(LinkedListNode<E>* node) {
zgu@7074 353 assert(node != NULL, "NULL pointer");
zgu@7074 354 LinkedListNode<E>* tmp = this->head();
zgu@7074 355 LinkedListNode<E>* prev = NULL;
zgu@7074 356
zgu@7074 357 int cmp_val;
zgu@7074 358 while (tmp != NULL) {
zgu@7074 359 cmp_val = FUNC(*tmp->peek(), *node->peek());
zgu@7074 360 if (cmp_val >= 0) {
zgu@7074 361 break;
zgu@7074 362 }
zgu@7074 363 prev = tmp;
zgu@7074 364 tmp = tmp->next();
zgu@7074 365 }
zgu@7074 366
zgu@7074 367 if (prev != NULL) {
zgu@7074 368 node->set_next(prev->next());
zgu@7074 369 prev->set_next(node);
zgu@7074 370 } else {
zgu@7074 371 node->set_next(this->head());
zgu@7074 372 this->set_head(node);
zgu@7074 373 }
zgu@7074 374 }
zgu@7074 375
zgu@7074 376 virtual bool add(const LinkedList<E>* list) {
zgu@7074 377 return LinkedListImpl<E, T, F, alloc_failmode>::add(list);
zgu@7074 378 }
zgu@7074 379
zgu@7074 380 virtual LinkedListNode<E>* find_node(const E& e) {
zgu@7074 381 LinkedListNode<E>* p = this->head();
zgu@7074 382
zgu@7074 383 while (p != NULL) {
zgu@7074 384 int comp_val = FUNC(*p->peek(), e);
zgu@7074 385 if (comp_val == 0) {
zgu@7074 386 return p;
zgu@7074 387 } else if (comp_val > 0) {
zgu@7074 388 return NULL;
zgu@7074 389 }
zgu@7074 390 p = p->next();
zgu@7074 391 }
zgu@7074 392 return NULL;
zgu@7074 393 }
zgu@7074 394 };
zgu@7074 395
zgu@7074 396 // Iterates all entries in the list
zgu@7074 397 template <class E> class LinkedListIterator : public StackObj {
zgu@7074 398 private:
zgu@7074 399 LinkedListNode<E>* _p;
zgu@7074 400 bool _is_empty;
zgu@7074 401 public:
zgu@7074 402 LinkedListIterator(LinkedListNode<E>* head) : _p(head) {
zgu@7074 403 _is_empty = (head == NULL);
zgu@7074 404 }
zgu@7074 405
zgu@7074 406 bool is_empty() const { return _is_empty; }
zgu@7074 407
zgu@7074 408 const E* next() {
zgu@7074 409 if (_p == NULL) return NULL;
zgu@7074 410 const E* e = _p->peek();
zgu@7074 411 _p = _p->next();
zgu@7074 412 return e;
zgu@7074 413 }
zgu@7074 414 };
zgu@7074 415
zgu@7074 416 #endif

mercurial