00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 {
00031 protected:
00032 HeapChunk* _next, *_prev;
00033 void initialize() { _next = _prev = this; size = 0; }
00034 public:
00035 int size;
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
00076 # define maxOneByteLen (usedOvfl - used)
00077
00078
00079
00080
00081
00082
00083
00084
00085
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() {
00113 int ovfl = isUsed() ? usedOvfl: unusedOvfl;
00114 return c(0) == ovfl ? maxHeaderSize : minHeaderSize;
00115 }
00116 int size() {
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
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
00160 if (s == unused) {
00161
00162
00163
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
00173
00174
00175 for ( ; i < nChunks - maxHeaderSize; i++) p[i] = MaxDistance - maxHeaderSize;
00176 }
00177 }
00178 }
00179
00180 ChunkKlass* ChunkKlass::findStart(ChunkKlass* mapStart, ChunkKlass* mapEnd) {
00181
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
00188 while (*p < MaxDistance) p -= *p;
00189 assert(p >= start, "not found");
00190 m = asChunkKlass(p);
00191 } else {
00192
00193
00194
00195
00196 while (*p >= MaxDistance && p < end) p++;
00197 if (p < end) {
00198
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
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
00282 bytesUsed = 0;
00283 total = 0;
00284 ifrag = 0;
00285
00286
00287 for(int i = 0; i < nfree; i++) {
00288 freeList[i].clear();
00289 }
00290 bigList->clear();
00291
00292
00293 heapKlass->markUnused(mapSize());
00294 heapEnd()->markUsed(1);
00295 asChunkKlass(heapKlass->asByte() - 1)->markUsed(1);
00296
00297
00298 addToFreeList(heapKlass);
00299
00300
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);
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);
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()) {
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);
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
00449
00450
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();
00459 while (cm1->isUnused()) {
00460 ChunkKlass* free = cm1;
00461 cm1 = free->prev();
00462 removeFromFreeList(free);
00463 free->invalidate();
00464 }
00465 cm1 = cm1->next();
00466 }
00467 ChunkKlass* cm2 = cmnext;
00468 while (cm2->isUnused()) {
00469 ChunkKlass* free = cm2;
00470 cm2 = cm2->next();
00471 removeFromFreeList(free);
00472 free->invalidate();
00473 }
00474
00475
00476
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
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
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
00530
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;
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
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
00583 while (m < end) {
00584 if (!m->verify()) lprintf(" in heap %#lx", this);
00585 m = m->next();
00586 }
00587
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