zoneHeap.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, LongView Technologies L.L.C. $Revision: 1.12 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 # include "incls/_precompiled.incl"
00025 
00026 #ifdef DELTA_COMPILER
00027 
00028 # include "incls/_zoneHeap.cpp.incl"
00029 
00030 class HeapChunk : public ValueObj {     // a heap chunk is a consecutive sequence of blocks
00031  protected:
00032   HeapChunk* _next, *_prev;  // doubly-linked ring
00033   void initialize() { _next = _prev = this; size = 0; }
00034  public:
00035   int size;     // size in blocks (only for heterogenuous list)
00036   
00037   HeapChunk() { initialize(); }
00038 
00039   HeapChunk* next() const { return _next; }
00040   HeapChunk* prev() const { return _prev; }
00041 
00042   void insert(HeapChunk* other) { 
00043     other->_next = _next;
00044     _next->_prev = other;
00045     _next = other;
00046     other->_prev = this; 
00047   }
00048 
00049   void remove() {
00050     _next->_prev = _prev;
00051     _prev->_next = _next;
00052     initialize(); 
00053   }
00054 };
00055 
00056 class FreeList: private HeapChunk {
00057  public:
00058   void clear() { initialize(); }
00059 
00060   HeapChunk* anchor() const { return (HeapChunk*)this; }
00061   bool isEmpty() const { return next() == anchor(); }
00062   void append(HeapChunk* h);
00063   void remove(HeapChunk* h);
00064   HeapChunk* get();
00065   int length() const;
00066 };
00067 
00068 
00069 enum chunkState {
00070   ZeroDistance = 0, MaxDistance = 128,
00071   unused = 128, unusedOvfl = 190,
00072   used = 192, usedOvfl = 254,
00073   invalid = 255};
00074 
00075 # define MaxDistLog    7  /* log2(MaxDistance) */
00076 # define maxOneByteLen (usedOvfl - used)
00077 
00078 // format of chunks in free map: first & last byte hold chunk size
00079 // unused..unusedOvfl-1:unused, length n+1
00080 // used..usedOvfl-1     used, length n - used + 1
00081 // unusedOvfl:          unused, encoded length in next (prev) 3 bytes
00082 // usedOvfl:            used, encoded length in next (prev) 3 bytes
00083 
00084 // The other bytes hold the distance to the chunk header (or an approximation
00085 // thereof); headers are found by following the distance pointers downwards
00086 
00087 const int minHeaderSize = 1;
00088 const int maxHeaderSize = 4;
00089 
00090 class ChunkKlass;
00091 inline ChunkKlass* asChunkKlass(u_char* c)      { return (ChunkKlass*)c; }
00092 
00093 class ChunkKlass {
00094   u_char c(int which)           { return ((u_char*)this)[which]; }
00095   u_char n(int which)           { return c(which) - unused; }
00096  public:
00097   ChunkKlass()                          { fatal("shouldn't create"); }
00098   u_char* asByte()                      { return (u_char*)this; }
00099   void markSize(int nChunks, chunkState s);
00100   void markUsed(int nChunks)            { markSize(nChunks, used); }
00101   void markUnused(int nChunks)  { markSize(nChunks, unused); }
00102   ChunkKlass* findStart(ChunkKlass* mapStart, ChunkKlass* mapEnd);
00103   
00104   bool verify();
00105   void print();
00106   bool isValid();
00107   void invalidate()                     { asByte()[0] = invalid; }
00108   
00109   chunkState state()                    { return chunkState(c(0)); }
00110   bool isUsed()                         { return state() >= used; }
00111   bool isUnused()                       { return ! isUsed(); }
00112   int headerSize() {            // size of header in bytes
00113     int ovfl = isUsed() ? usedOvfl: unusedOvfl;
00114     return c(0) == ovfl ? maxHeaderSize : minHeaderSize;
00115   }
00116   int size() {          // size of this block
00117     int ovfl = isUsed() ? usedOvfl: unusedOvfl;
00118     int len;
00119     assert(c(0) != invalid && c(0) >= MaxDistance, "invalid chunk");
00120     if (c(0) != ovfl) {
00121       len = c(0) + 1 - (isUsed() ? used : unused);
00122     } else {
00123       len = (((n(1) << MaxDistLog) + n(2)) << MaxDistLog) + n(3);
00124     }
00125     assert(len > 0, "negative/zero chunk length");
00126     return len;
00127   }
00128   bool contains(u_char* p) { return asByte() <= p && p < asByte() + size(); }
00129   ChunkKlass*  next() { return asChunkKlass(asByte()+size()); }
00130   ChunkKlass*  prev() {
00131     ChunkKlass* p = asChunkKlass(asByte() - 1);
00132     int ovfl = p->isUsed() ? usedOvfl: unusedOvfl;
00133     int len;
00134     if (c(-1) != ovfl) {
00135       len = p->size();
00136     } else {
00137       len = (((n(-4) << MaxDistLog) + n(-3)) << MaxDistLog) + n(-2);
00138     }
00139     assert(len > 0, "negative/zero chunk length");
00140     return asChunkKlass(asByte() - len);
00141   }
00142 };
00143 
00144 void ChunkKlass::markSize(int nChunks, chunkState s) {
00145   // write header
00146   u_char* p = asByte();
00147   u_char* e = p + nChunks - 1;
00148   if (nChunks < maxOneByteLen) {
00149     p[0] = e[0] = s + nChunks - 1;
00150   } else {
00151     assert(nChunks < (1<<(3*MaxDistLog)), "chunk too large");
00152     unsigned mask = nthMask(MaxDistLog);
00153     p[0] = e[0] = (s == used) ? usedOvfl : unusedOvfl;
00154     p[1] = e[-3] = unused +  (nChunks >> (2*MaxDistLog));
00155     p[2] = e[-2] = unused + ((nChunks >>    MaxDistLog) & mask);
00156     p[3] = e[-1] = unused + ( nChunks                   & mask);
00157   }
00158   assert(size() == nChunks, "incorrect size encoding");
00159   // mark distance for used blocks
00160   if (s == unused) {
00161     // don't mark unused blocks - not necessary, and would be a performance 
00162     // bug (start: *huge* free block, shrinks with every alloc -> quadratic)
00163     // however, the first distance byte must be correct (for findStart)
00164     if (nChunks > 2 * minHeaderSize) p[headerSize()] = headerSize();
00165   } else {
00166     if (nChunks < maxOneByteLen) {
00167       assert(maxOneByteLen <= MaxDistance, "oops!");
00168       for (int i = minHeaderSize; i < nChunks - minHeaderSize; i++) p[i] = i;
00169     } else {
00170       int max = min(nChunks - 4, MaxDistance);
00171       for (int i = maxHeaderSize; i < max; i++) p[i] = i;
00172       // fill rest with large distance values (don't use MaxDistance - 1 because
00173       // the elems MaxDistance..MaxDistance+maxHeaderSize-1 would point *into*
00174       // the header)
00175       for ( ; i < nChunks - maxHeaderSize; i++) p[i] = MaxDistance - maxHeaderSize;
00176     }
00177   }
00178 }
00179 
00180 ChunkKlass* ChunkKlass::findStart(ChunkKlass* mapStart, ChunkKlass* mapEnd) {
00181   // this points into the middle of a chunk; return start of chunk
00182   u_char* p = asByte();
00183   u_char* start = mapStart->asByte();
00184   u_char* end   = mapEnd  ->asByte();
00185   ChunkKlass* m;
00186   if (*p < MaxDistance) {
00187     // we're outside the header, so just walk down the trail
00188     while (*p < MaxDistance) p -= *p;
00189     assert(p >= start, "not found");
00190     m = asChunkKlass(p);
00191   } else {
00192     // pointing to a header, but we don't know whether long/short etc
00193     // first walk up to first non-header byte
00194     // (note that first distance byte of unused blocks is correct, but
00195     // the others aren't)
00196     while (*p >= MaxDistance && p < end) p++;
00197     if (p < end) {
00198       // find start of this block
00199       while (*p < MaxDistance) p -= *p;
00200       assert(p >= start, "not found");
00201     }
00202     m = asChunkKlass(p);
00203     while (! m->contains(this->asByte())) m = m->prev();
00204   }
00205   assert(m->verify(), "invalid chunk map");
00206   assert(m->contains(this->asByte()), "wrong chunk");
00207   return m;
00208 }
00209 
00210 bool ChunkKlass::isValid() {
00211   u_char* p = asByte();
00212   bool ok;
00213   if (p[0] == invalid || p[0] < MaxDistance) {
00214     ok = false;
00215   } else {
00216     u_char* e = next()->asByte() - 1;
00217     int ovfl = isUsed() ? usedOvfl: unusedOvfl;
00218     ok = p[0] == e[0] &&
00219         (p[0] != ovfl || p[1] == e[-3] && p[2] == e[-2] && p[3] == e[-1]);
00220   }
00221   return ok;
00222 }
00223 
00224 void ChunkKlass::print() {
00225   lprintf("chunk [%#lx..%#lx[\n", this, next());
00226 }
00227 
00228 bool ChunkKlass::verify() {
00229   if (! isValid()) {
00230     error("inconsistent chunk map %#lx", this);
00231     return false;
00232   }
00233   return true;
00234 }
00235 
00236 void FreeList::append(HeapChunk* h) {
00237   insert(h);
00238 }
00239 
00240 void FreeList::remove(HeapChunk* h) {
00241   h->remove();
00242 }
00243   
00244 HeapChunk* FreeList::get() {
00245   if (isEmpty()) {
00246     return NULL;
00247   } else {
00248     HeapChunk* res = anchor()->next();
00249     remove(res);
00250     return res;
00251   } 
00252 }
00253 
00254 int FreeList::length() const {
00255   int i = 0;
00256   HeapChunk* f = anchor();
00257   for (HeapChunk* p = f->next(); p != f; p = p->next()) i++;
00258   return i;
00259 }
00260 
00261 Heap::Heap(int s, int bs) {
00262   assert(s % bs == 0, "size not a multiple of blockSize");
00263   size = s;
00264   if (bs & (bs - 1)) fatal1("heap block size (%ld) isn't power of 2", bs);
00265   blockSize = bs;
00266   log2BS = 0;
00267   while (bs > 1) { bs >>= 1; log2BS++; }
00268   nfree = 30;
00269   _base = AllocateHeap(size + blockSize, "zone");
00270   base = (char*)((int(_base) + blockSize - 1) / blockSize * blockSize);
00271   assert(int(base) % blockSize == 0, "base not aligned to blockSize");
00272   heapKlass = (ChunkKlass*)(AllocateHeap(mapSize() + 2, "zone free map") + 1);
00273   // + 2 for sentinels
00274   freeList = NEW_C_HEAP_ARRAY( FreeList, nfree);
00275   bigList  = NEW_C_HEAP_OBJ(FreeList);
00276   newHeap = NULL;
00277   clear();
00278 }
00279 
00280 void Heap::clear() {
00281   // initialize the statistics
00282   bytesUsed = 0;
00283   total     = 0;
00284   ifrag     = 0;
00285 
00286   // initialize the free lists
00287   for(int i = 0; i < nfree; i++) {
00288     freeList[i].clear();
00289   }
00290   bigList->clear();
00291 
00292   // initialize the map
00293   heapKlass->markUnused(mapSize());                   // mark everything as unused
00294   heapEnd()->markUsed(1);                             // start sentinel
00295   asChunkKlass(heapKlass->asByte() - 1)->markUsed(1); // stop sentinel
00296 
00297   // add whole chunk to free list
00298   addToFreeList(heapKlass);
00299 
00300   // set the combine variables
00301   combineMode = false;
00302   lastCombine = heapKlass;
00303 }
00304 
00305 Heap::~Heap() {
00306 # ifdef ASSERT
00307     set_oops((oop*)base, capacity() / oopSize, NULL);
00308 # endif
00309   free(_base);
00310   free(heapKlass - 1);      // -1 to get rid of sentinel
00311   free(freeList);
00312   free(bigList);
00313 }
00314 
00315 void Heap::removeFromFreeList(ChunkKlass* m) {
00316 # ifdef ASSERT
00317     m->verify();
00318 # endif
00319   HeapChunk* p = (HeapChunk*)blockAddr(m);
00320   p->remove();
00321 }
00322 
00323 bool Heap::addToFreeList(ChunkKlass* m) {
00324 # ifdef ASSERT
00325     m->verify();
00326 # endif
00327   HeapChunk* p = (HeapChunk*)blockAddr(m);
00328   int sz = m->size();
00329   if (sz <= nfree) {
00330     freeList[sz-1].append(p);
00331     return false;
00332   } else {
00333     bigList->append(p);
00334     p->size = sz;
00335     return true;
00336   }
00337 }
00338 
00339 void* Heap::allocFromLists(int wantedBytes) {
00340   assert(wantedBytes % blockSize == 0, "not a multiple of blockSize");
00341   int wantedBlocks = wantedBytes >> log2BS;
00342   assert(wantedBlocks > 0, "negative alloc size");
00343   int blocks = wantedBlocks - 1;
00344   void* p = NULL;
00345   while (!p && ++blocks <= nfree) {
00346     p = freeList[blocks-1].get();
00347   }
00348   if (! p) {
00349     HeapChunk* f = bigList->anchor();
00350     for (HeapChunk* c = f->next();
00351          c != f && c->size < wantedBlocks;
00352          c = c->next());
00353     if (c == f) {
00354       if (! combineMode && combineAll() >= wantedBlocks)
00355         return allocFromLists(wantedBytes);
00356     } else {
00357       p = (void*)c;
00358       blocks = c->size;
00359       bigList->remove(c);
00360     }
00361   } 
00362   if (p) {
00363     ChunkKlass* m = mapAddr(p);
00364     assert(m->size() == blocks, "inconsistent sizes");
00365     m->markUsed(wantedBlocks);
00366     if (blocks > wantedBlocks) {
00367 #ifdef LOG_LOTSA_STUFF
00368       if (!bootstrapping) LOG_EVENT("zoneHeap: splitting allocated block");
00369 #endif
00370       int freeChunkSize = blocks - wantedBlocks;
00371       ChunkKlass* freeChunk = m->next();
00372       freeChunk->markUnused(freeChunkSize);
00373       addToFreeList(freeChunk);
00374     }
00375   }
00376   return p;
00377 }
00378 
00379 void* Heap::allocate(int wantedBytes) {
00380   assert(wantedBytes > 0, "Heap::allocate: size <= 0");
00381   int rounded = ((wantedBytes + blockSize - 1) >> log2BS) << log2BS;
00382   
00383   void* p = allocFromLists(rounded);
00384   if (p) {
00385     bytesUsed += rounded;
00386     total += rounded;
00387     ifrag += rounded - wantedBytes;
00388   }
00389   if (VerifyZoneOften) {
00390     verify();
00391   }
00392   return p;
00393 }
00394 
00395 
00396 void Heap::deallocate(void* p, int bytes) {
00397   ChunkKlass* m = mapAddr(p);
00398   int myChunkSize = m->size();
00399   int blockedBytes = myChunkSize << log2BS;
00400   bytesUsed -= blockedBytes;
00401   ifrag -= blockedBytes - bytes;
00402   m->markUnused(myChunkSize);
00403   bool big = addToFreeList(m);
00404   HeapChunk* c = (HeapChunk*)p;
00405   if (combineMode || big) combine(c);   // always keep bigList combined
00406 
00407   if (VerifyZoneOften) {
00408     verify();
00409   }
00410 }
00411 
00412 # define INC(p, n)   p = asChunkKlass(p->asByte() + n)
00413 
00414 char* Heap::compact(void move(char* from, char* to, int nbytes)) {
00415   if (usedBytes() == capacity()) return NULL;
00416   
00417   ChunkKlass* m = heapKlass;
00418   ChunkKlass* end = heapEnd();
00419   
00420   ChunkKlass* freeChunk = m;
00421   while (freeChunk->isUsed()) {                         // find 1st unused blk
00422     freeChunk = freeChunk->next();
00423   }
00424   ChunkKlass* usedChunk = freeChunk;
00425   
00426   for(;;) {
00427     while (usedChunk->isUnused()) usedChunk = usedChunk->next();
00428     if (usedChunk == end) break;
00429     int uSize = usedChunk->size();
00430     assert(freeChunk < usedChunk, "compaction bug");
00431     move(blockAddr(usedChunk), blockAddr(freeChunk), uSize << log2BS);
00432     freeChunk->markUsed(uSize);   // must come *after* move
00433     INC(freeChunk, uSize);
00434     INC(usedChunk, uSize);
00435   }
00436   for(int i = 0; i < nfree; i++) freeList[i].clear();
00437   bigList->clear();
00438   int freeBlocks = end->asByte() - freeChunk->asByte();
00439   freeChunk->markUnused(freeBlocks);
00440   addToFreeList(freeChunk);
00441   assert(freeBlocks * blockSize == capacity() - usedBytes(),
00442          "usage info inconsistent");
00443   lastCombine = heapKlass;
00444   return blockAddr(freeChunk);
00445 }  
00446 
00447 int Heap::combine(HeapChunk*& c) {
00448   // Try to combine c with its neighbors; on return, c will point to
00449   // the next element in the freeList, and the return value will indicate
00450   // the size of the combined block.
00451   ChunkKlass* cm = mapAddr((char*)c);
00452   assert(cm < heapEnd(), "beyond heap");
00453   ChunkKlass* cmnext = cm->next();
00454   ChunkKlass* cm1;
00455   if (cm == heapKlass) {
00456     cm1 = cm;
00457   } else {
00458     cm1 = cm->prev();                   // try to combine with prev
00459     while (cm1->isUnused()) {           // will terminate because of sentinel
00460       ChunkKlass* free = cm1;
00461       cm1 = free->prev();
00462       removeFromFreeList(free);
00463       free->invalidate();               // make sure it doesn't look valid
00464     }
00465     cm1 = cm1->next();
00466   }
00467   ChunkKlass* cm2 = cmnext;             // try to combine with next
00468   while (cm2->isUnused()) {             // will terminate because of sentinel
00469     ChunkKlass* free = cm2;
00470     cm2 = cm2->next();
00471     removeFromFreeList(free);
00472     free->invalidate();                 // make sure it doesn't look valid
00473   }
00474 
00475   // The combined block will move to a new free list; make sure that c
00476   // returns an element in the current list so that iterators work.
00477   c = c->next();
00478 
00479   if (cm1 != cm || cm2 != cmnext) {
00480     removeFromFreeList(cm);
00481     cm->invalidate();   
00482     cm1->markUnused(cm2->asByte() - cm1->asByte());
00483     addToFreeList(cm1);
00484     lastCombine = cm1;
00485   }
00486   assert(cm1 >= heapKlass && cm2 <= heapEnd() && cm1 < cm2, "just checkin'");
00487   return cm1->size();
00488 }
00489 
00490 // Try to combine adjacent free chunks; return size of biggest chunk (in blks).
00491 int Heap::combineAll() {
00492   int biggest = 0;
00493   for (int i = 0; i < nfree; i++) {
00494     HeapChunk* f = freeList[i].anchor();
00495     for (HeapChunk* c = f->next(); c != f; ) {
00496       HeapChunk* c1 = c;
00497       int sz = combine(c);
00498       if (c1 == c) fatal("infinite loop detected while combining blocks");
00499       if (sz > biggest) biggest = sz;
00500     }
00501   }
00502   combineMode = true;
00503   if (VerifyZoneOften) {
00504     verify();
00505   }
00506   return biggest;
00507 }
00508 
00509 void* Heap::firstUsed() const {
00510   if (usedBytes() == 0) return NULL;
00511   if (heapKlass->isUsed()) {
00512     return base;
00513   } else {
00514     return nextUsed(base);
00515   }
00516 }
00517 
00518 // return next used chunk with address > p
00519 void* Heap::nextUsed(void* p) const {
00520   ChunkKlass* m = mapAddr(p);
00521   if (m->isValid() && !lastCombine->contains(m->asByte())) {
00522     if (VerifyZoneOften) {
00523       for (ChunkKlass* m1 = heapKlass; m1 < m; m1 = m1->next()) ;
00524       assert(m1 == m, "m isn't a valid chunk");
00525     }
00526     assert(m->verify(), "valid chunk doesn't verify");
00527     m = m->next();
00528   } else {
00529     // m is pointing into the middle of a block (because of block
00530     // combination)
00531 #   ifdef ASSERT
00532       for (ChunkKlass* m1 = heapKlass; m1 < lastCombine; m1 = m1->next()) ;
00533       assert(m1 == lastCombine, "lastCombine not found");
00534       assert(lastCombine->verify(), "invalid lastCombine");
00535 #   endif
00536     for (ChunkKlass* n = lastCombine; n <= m; n = n->next()) ;
00537     m = n;
00538     assert(m->isValid(), "something's wrong");
00539   }
00540   
00541   while (m->isUnused()) {
00542     m = m->next();
00543   } 
00544   
00545   assert(m->isValid(), "something's wrong");
00546   assert(m <= heapEnd(), "past end of heap");
00547   if (m == heapEnd()) {
00548     return NULL;                                        // was last one
00549   } else {
00550     void* next = blockAddr(m);
00551     assert(next > p, "must be monotonic");
00552     assert(!(int(next) & 1), "must be even");
00553     return next;
00554   }
00555 }
00556 
00557 void* Heap::findStartOfBlock(void* start) const {
00558   // used a lot -- help the optimizer a bit
00559   if (newHeap && newHeap->contains(start))
00560     return newHeap->findStartOfBlock(start);
00561   
00562   const int  blockSz = blockSize;       
00563   start = (void*)(int(start) & ~(blockSz-1));
00564   assert(contains(start), "start not in this zone");
00565   ChunkKlass* m = mapAddr(start)->findStart(heapKlass, heapEnd());
00566   return blockAddr(m);
00567 }
00568 
00569 int Heap::sizeOfBlock(void* p) const {
00570   return mapAddr(p)->size() << log2BS;
00571 }
00572 
00573 void Heap::verify() const {
00574   ChunkKlass* m = heapKlass;
00575   ChunkKlass* end = heapEnd();
00576   if (end->isUnused() || end->size() != 1)
00577     error("wrong end-sentinel %d in heap %#lx", *(u_char*)end, this);
00578   ChunkKlass* begin = asChunkKlass(heapKlass->asByte() - 1);
00579   if (begin->isUnused() || begin->size() != 1)
00580     error("wrong begin-sentinel %d in heap %#lx", *(u_char*)begin, this);
00581   
00582   // verify map structure
00583   while (m < end) {
00584     if (!m->verify()) lprintf(" in heap %#lx", this);
00585     m = m->next();
00586   }
00587   // verify free lists
00588   for (int i = 0; i < nfree; i++) {
00589     int j = 0;
00590     int lastSize = 0;
00591     HeapChunk* f = freeList[i].anchor();
00592     for(HeapChunk* h = f->next(); h != f; h = h->next(), j++) {
00593       ChunkKlass* p = mapAddr(h);
00594       if (!p->verify())
00595         lprintf(" in free list %ld (elem %ld) of heap %#lx", i, j, this);
00596       if (p->isUsed()) {
00597         error("inconsistent freeList %ld elem %#lx in heap %#lx (map %#lx)",
00598                i, h, this, p);
00599       }
00600       if (p->size() != lastSize && j != 0) {
00601         error("freeList %ld elem %#lx in heap %#lx (map %#lx) has wrong size",
00602                i, h, this, p);
00603       }
00604       lastSize = p->size();
00605       if (h->next() == h) {
00606         error("loop in freeList %ld elem %#lx in heap %#lx", i, h, this);
00607         break;
00608       }
00609     }
00610   }
00611   int j = 0;
00612   HeapChunk* f = bigList->anchor();
00613   for(HeapChunk* h = f->next(); h != f; h = h->next(), j++) {
00614     ChunkKlass* p = mapAddr(h);
00615     if (!p->verify())
00616       lprintf(" in bigList (elem %ld) of heap %#lx", j, this);
00617     if (p->isUsed()) {
00618       error("inconsistent freeList %ld elem %#lx in heap %#lx (map 0xlx)",
00619              i, h, this, p);
00620     }
00621   }
00622   if (! lastCombine->verify())
00623     error("invalid lastCombine in heap %#lx", this);
00624   
00625 }
00626 
00627 void Heap::print() const {
00628   lprintf("%#lx: [%#lx..%#lx)\n", this, base, base + capacity());
00629   printIndent();
00630   lprintf("  size %ld (blk %ld), used %ld (%1.1f%%), ifrag %1.1f%%;\n",
00631          capacity(), blockSize, usedBytes(),
00632          100.0 * usedBytes() / capacity(), 100.0 * intFrag());
00633   printIndent();
00634   lprintf("  grand total allocs = %ld bytes\n", total);
00635   printIndent();
00636   lprintf("  free lists: ");
00637   for (int i = 0; i < nfree; i++) lprintf("%ld ", freeList[i].length());
00638   lprintf("; %ld\n", bigList->length());
00639 }
00640 
00641 #endif

Generated on Mon Oct 9 13:37:31 2006 for Strongtalk VM by  doxygen 1.4.7