1 #ifdef USE_PRAGMA_IDENT_SRC
   2 #pragma ident "@(#)freeList.cpp 1.31 07/05/05 17:05:48 JVM"
   3 #endif
   4 /*
   5  * Copyright 2001-2006 Sun Microsystems, Inc.  All Rights Reserved.
   6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   7  *
   8  * This code is free software; you can redistribute it and/or modify it
   9  * under the terms of the GNU General Public License version 2 only, as
  10  * published by the Free Software Foundation.
  11  *
  12  * This code is distributed in the hope that it will be useful, but WITHOUT
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15  * version 2 for more details (a copy is included in the LICENSE file that
  16  * accompanied this code).
  17  *
  18  * You should have received a copy of the GNU General Public License version
  19  * 2 along with this work; if not, write to the Free Software Foundation,
  20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21  *
  22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  23  * CA 95054 USA or visit www.sun.com if you need additional information or
  24  * have any questions.
  25  *  
  26  */
  27 
  28 # include "incls/_precompiled.incl"
  29 # include "incls/_freeList.cpp.incl"
  30 
  31 // Free list.  A FreeList is used to access a linked list of chunks
  32 // of space in the heap.  The head and tail are maintained so that
  33 // items can be (as in the current implementation) added at the 
  34 // at the tail of the list and removed from the head of the list to
  35 // maintain a FIFO queue.
  36 
  37 FreeList::FreeList() :
  38   _head(NULL), _tail(NULL)
  39 #ifdef ASSERT
  40   , _protecting_lock(NULL)
  41 #endif
  42 {
  43   _size         = 0;
  44   _count        = 0;
  45   _hint         = 0;
  46   init_statistics();
  47 }
  48 
  49 FreeList::FreeList(FreeChunk* fc) :
  50   _head(fc), _tail(fc)
  51 #ifdef ASSERT
  52   , _protecting_lock(NULL)
  53 #endif
  54 {
  55   _size         = fc->size();
  56   _count        = 1;
  57   _hint         = 0;
  58   init_statistics();
  59 #ifndef PRODUCT
  60   _allocation_stats.set_returnedBytes(size() * HeapWordSize);
  61 #endif
  62 }
  63 
  64 FreeList::FreeList(HeapWord* addr, size_t size) :
  65   _head((FreeChunk*) addr), _tail((FreeChunk*) addr)
  66 #ifdef ASSERT
  67   , _protecting_lock(NULL)
  68 #endif
  69 {
  70   assert(size > sizeof(FreeChunk), "size is too small");
  71   head()->setSize(size);
  72   _size         = size;
  73   _count        = 1;
  74   init_statistics();
  75 #ifndef PRODUCT
  76   _allocation_stats.set_returnedBytes(_size * HeapWordSize);
  77 #endif
  78 }
  79 
  80 void FreeList::reset(size_t hint) {
  81   set_count(0);
  82   set_head(NULL);
  83   set_tail(NULL);
  84   set_hint(hint);
  85 }
  86 
  87 void FreeList::init_statistics() {
  88   _allocation_stats.initialize();
  89 }
  90 
  91 FreeChunk* FreeList::getChunkAtHead() {
  92   assert_proper_lock_protection();
  93   assert(head() == NULL || head()->prev() == NULL, "list invariant");
  94   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
  95   FreeChunk* fc = head();
  96   if (fc != NULL) {
  97     FreeChunk* nextFC = fc->next();
  98     if (nextFC != NULL) {
  99       // The chunk fc being removed has a "next".  Set the "next" to the
 100       // "prev" of fc.
 101       nextFC->linkPrev(NULL);
 102     } else { // removed tail of list
 103       link_tail(NULL);
 104     }
 105     link_head(nextFC);
 106     decrement_count();
 107   }
 108   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 109   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 110   return fc;
 111 }
 112 
 113 
 114 void FreeList::getFirstNChunksFromList(size_t n, FreeList* fl) {
 115   assert_proper_lock_protection();
 116   assert(fl->count() == 0, "Precondition");
 117   if (count() > 0) {
 118     int k = 1;
 119     fl->set_head(head()); n--;
 120     FreeChunk* tl = head();
 121     while (tl->next() != NULL && n > 0) {
 122       tl = tl->next(); n--; k++;
 123     }
 124     assert(tl != NULL, "Loop Inv.");
 125     
 126     // First, fix up the list we took from.
 127     FreeChunk* new_head = tl->next();
 128     set_head(new_head);
 129     set_count(count() - k);
 130     if (new_head == NULL) {
 131       set_tail(NULL);
 132     } else {
 133       new_head->linkPrev(NULL);
 134     }
 135     // Now we can fix up the tail.
 136     tl->linkNext(NULL);
 137     // And return the result.
 138     fl->set_tail(tl);
 139     fl->set_count(k);
 140   }
 141 }
 142 
 143 // Remove this chunk from the list
 144 void FreeList::removeChunk(FreeChunk*fc) {
 145    assert_proper_lock_protection();
 146    assert(head() != NULL, "Remove from empty list");
 147    assert(fc != NULL, "Remove a NULL chunk");
 148    assert(size() == fc->size(), "Wrong list");
 149    assert(head() == NULL || head()->prev() == NULL, "list invariant");
 150    assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 151 
 152    FreeChunk* prevFC = fc->prev();
 153    FreeChunk* nextFC = fc->next();
 154    if (nextFC != NULL) {
 155      // The chunk fc being removed has a "next".  Set the "next" to the
 156      // "prev" of fc.
 157      nextFC->linkPrev(prevFC);
 158    } else { // removed tail of list
 159      link_tail(prevFC);
 160    }
 161    if (prevFC == NULL) { // removed head of list
 162      link_head(nextFC);
 163      assert(nextFC == NULL || nextFC->prev() == NULL, 
 164        "Prev of head should be NULL");
 165    } else {
 166      prevFC->linkNext(nextFC);
 167      assert(tail() != prevFC || prevFC->next() == NULL,
 168        "Next of tail should be NULL");
 169    }
 170    decrement_count();
 171 #define TRAP_CODE 1
 172 #if TRAP_CODE
 173    if (head() == NULL) {
 174      guarantee(tail() == NULL, "INVARIANT");
 175      guarantee(count() == 0, "INVARIANT");
 176    }
 177 #endif
 178    // clear next and prev fields of fc, debug only
 179    NOT_PRODUCT(
 180      fc->linkPrev(NULL);
 181      fc->linkNext(NULL);
 182    )
 183    assert(fc->isFree(), "Should still be a free chunk");
 184    assert(head() == NULL || head()->prev() == NULL, "list invariant");
 185    assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 186    assert(head() == NULL || head()->size() == size(), "wrong item on list");
 187    assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
 188 }
 189 
 190 // Add this chunk at the head of the list.
 191 void FreeList::returnChunkAtHead(FreeChunk* chunk, bool record_return) {
 192   assert_proper_lock_protection();
 193   assert(chunk != NULL, "insert a NULL chunk");
 194   assert(size() == chunk->size(), "Wrong size");
 195   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 196   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 197   
 198   FreeChunk* oldHead = head();
 199   assert(chunk != oldHead, "double insertion");
 200   chunk->linkAfter(oldHead);
 201   link_head(chunk);
 202   if (oldHead == NULL) { // only chunk in list
 203     assert(tail() == NULL, "inconsistent FreeList");
 204     link_tail(chunk);
 205   }
 206   increment_count(); // of # of chunks in list
 207   DEBUG_ONLY(
 208     if (record_return) {
 209       increment_returnedBytes_by(size()*HeapWordSize);
 210     }
 211   )
 212   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 213   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 214   assert(head() == NULL || head()->size() == size(), "wrong item on list");
 215   assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
 216 }
 217 
 218 void FreeList::returnChunkAtHead(FreeChunk* chunk) {
 219   assert_proper_lock_protection();
 220   returnChunkAtHead(chunk, true);
 221 }
 222 
 223 // Add this chunk at the tail of the list.
 224 void FreeList::returnChunkAtTail(FreeChunk* chunk, bool record_return) {
 225   assert_proper_lock_protection();
 226   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 227   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 228   assert(chunk != NULL, "insert a NULL chunk");
 229   assert(size() == chunk->size(), "wrong size");
 230 
 231   FreeChunk* oldTail = tail();
 232   assert(chunk != oldTail, "double insertion");
 233   if (oldTail != NULL) {
 234     oldTail->linkAfter(chunk);
 235   } else { // only chunk in list
 236     assert(head() == NULL, "inconsistent FreeList");
 237     link_head(chunk);
 238   }
 239   link_tail(chunk);
 240   increment_count();  // of # of chunks in list
 241   DEBUG_ONLY(
 242     if (record_return) {
 243       increment_returnedBytes_by(size()*HeapWordSize);
 244     }
 245   )
 246   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 247   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 248   assert(head() == NULL || head()->size() == size(), "wrong item on list");
 249   assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
 250 }
 251 
 252 void FreeList::returnChunkAtTail(FreeChunk* chunk) {
 253   returnChunkAtTail(chunk, true);
 254 }
 255 
 256 void FreeList::prepend(FreeList* fl) {
 257   assert_proper_lock_protection();
 258   if (fl->count() > 0) {
 259     if (count() == 0) {
 260       set_head(fl->head());
 261       set_tail(fl->tail());
 262       set_count(fl->count());
 263     } else {
 264       // Both are non-empty.
 265       FreeChunk* fl_tail = fl->tail();
 266       FreeChunk* this_head = head();
 267       assert(fl_tail->next() == NULL, "Well-formedness of fl");
 268       fl_tail->linkNext(this_head);
 269       this_head->linkPrev(fl_tail);
 270       set_head(fl->head());
 271       set_count(count() + fl->count());
 272     }
 273     fl->set_head(NULL);
 274     fl->set_tail(NULL);
 275     fl->set_count(0);
 276   }
 277 }
 278 
 279 // verifyChunkInFreeLists() is used to verify that an item is in this free list.
 280 // It is used as a debugging aid.
 281 bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const {
 282   // This is an internal consistency check, not part of the check that the
 283   // chunk is in the free lists.
 284   guarantee(fc->size() == size(), "Wrong list is being searched");
 285   FreeChunk* curFC = head();
 286   while (curFC) {
 287     // This is an internal consistency check.
 288     guarantee(size() == curFC->size(), "Chunk is in wrong list.");
 289     if (fc == curFC) {
 290       return true;
 291     }
 292     curFC = curFC->next();
 293   }
 294   return false;
 295 }
 296 
 297 #ifndef PRODUCT
 298 void FreeList::assert_proper_lock_protection_work() const {
 299 #ifdef ASSERT
 300   if (_protecting_lock != NULL &&
 301       SharedHeap::heap()->n_par_threads() > 0) {
 302     // Should become an assert.
 303     guarantee(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED");
 304   }
 305 #endif
 306 }
 307 #endif