zone.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, LongView Technologies L.L.C. $Revision: 1.39 $ */
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/_zone.cpp.incl"
00029 
00030 # define LRU_RESOLUTION     16  /* resolution (in secs) of LRU timer */
00031 
00032 # define LRU_RETIREMENT_AGE 10  /* min. age (# sweeps) for retirement */
00033 # define LRU_MAX_VISITED    min(numberOfNMethods(), LRUMaxVisited)
00034                                 /* max. # nmethods visited per sweep */
00035 # define LRU_MAX_RECLAIMED 250000 /* stop after having found this amount of */
00036                                 /* space occupied by replacement candidates */
00037 # define LRU_CUTOFF        32   /* max. length (bytes) of "small" methods */
00038 # define LRU_SMALL_BOOST    3   /* small methods live this many times longer */
00039          // (because access methods don't clear their unused bit)
00040 
00041 # define COMPACT_OVERHEAD  0.05 /* desired max. overhead for zone compaction */
00042 
00043 
00044 // Trade-offs for blocksizes/queue length below:
00045 // - larger blocks mean larger internal fragmentation but less space 
00046 //   overhead for the heap maps and increased effectiveness of the free lists
00047 // - longer free lists cover a wider range of allocations but can slow down
00048 //   allocation (when most lists are empty but still have to be scanned).
00049 # define CODE_BLOCK     64      /* block size for nmethods */
00050 # define PIC_BLOCK      32      /* block size for PICs */
00051 # define FREE   20              /* # of free lists */
00052 
00053 # define StubBlock  16          /* block size for PIC zone */
00054 # define StubFree   20          /* # of free lists for PIC zone */
00055 
00056 # define MaxExtFrag  0.05       /* max. tolerated ext. fragmentation */
00057 
00058 # define FOR_ALL_NMETHODS(var)                                                \
00059     for (nmethod *var = first_nm(); var; var = next_nm(var))
00060 
00061 
00062 # define FOR_ALL_PICS(var)                                                    \
00063     for (PIC *var = first_pic(); var; var = next_pic(var))
00064 
00065 inline int roundSize(int s, int blockSize) {
00066   return (s + blockSize - 1) / blockSize * blockSize;
00067 }
00068 
00069 LRUcount* LRUtable;     // for optimized methods
00070 int* LRUflag;           // == LRUtable, just different type for convenience
00071 
00072 static int LRUtime;         // virtual time; incremented after every full sweep
00073 
00074 // We could directly run the sweeper from the interrupt handler, but
00075 // this is tricky since the stack is in a strange state.  
00076 void sweepTrigger() {
00077   if (UseLRUInterrupts) {
00078     Universe::code->_needsSweep = true;
00079     // %note: should be:
00080     // currentProcess->setupPreemption();
00081   };
00082 }
00083 
00084 static void idOverflowError(int delta) {
00085   Unused(delta);
00086   // fix this - maybe eliminate nmethod IDs altogether?
00087   fatal("zone: nmethod ID table overflowed");
00088 }
00089 
00090 zone::zone(int& size) {
00091   methodHeap  = new Heap(Universe::current_sizes.code_size,     CODE_BLOCK);
00092   picHeap     = new Heap(Universe::current_sizes.pic_heap_size, PIC_BLOCK);
00093 
00094   methodTable = new codeTable(codeTableSize);
00095 
00096   // LRUflag = idManager->data;
00097   LRUtable = (LRUcount*)LRUflag;
00098   clear();
00099   
00100   // start sweeper
00101   // cpuTimer->enroll(sweepTrigger, 1.0 / LRU_RESOLUTION);
00102 }
00103 
00104 void zone::clear() {
00105   methodHeap->clear();
00106   picHeap->clear();
00107   methodTable->clear();
00108 
00109   LRUhand = NULL;
00110   LRUtime = 0;
00111   jump_table()->init();
00112   _needsCompaction = _needsSweep = false;
00113   compactTime = 0; compactDuration = 1; minFreeFrac = 0.05;
00114 }
00115 
00116 int zone::nextNMethodID() { return jump_table()->peekID(); }
00117 
00118 nmethod* zone::allocate(int size) {
00119   // CSect cs(profilerSemaphore); // for profiler
00120   // must get method ID here! (because reclaim might change firstFree)
00121   // (compiler may have used peekID to get ID of new nmethod for LRU stuff)
00122   if (needsSweep()) doSweep();
00123 
00124   nmethod* n = (nmethod*) methodHeap->allocate(size);
00125   
00126   if (n == NULL) {
00127     // allocation failed so flush zombies and retry
00128     flushZombies();
00129     n = (nmethod*) methodHeap->allocate(size);
00130     if (n == NULL) {
00131       print();
00132       fatal("cannot allocate enough space for nmethod");
00133     }
00134   }
00135 
00136   verify_if_often();
00137   return n;
00138 }
00139 
00140 int zone::used() {
00141   return methodHeap->usedBytes();
00142 }
00143 
00144 void zone::verify_if_often() {
00145   if (VerifyZoneOften) {
00146     methodHeap->verify();
00147   }
00148 }
00149 
00150 void zone::flush() {
00151   ResourceMark rm;
00152   TraceTime   t("Flushing method cache...", PrintCodeReclamation);
00153   EventMarker em("flushing method cache");
00154 
00155   // Deoptimize all stack frames
00156   Processes::deoptimize_all();
00157  
00158   FOR_ALL_NMETHODS(p) { p->makeZombie(true); }
00159   flushZombies();
00160 
00161   verify_if_often();
00162 }
00163 
00164 
00165 int zone::findReplCandidates(int needed) {
00166   // find replacement candidates; stop if > needed bytes found or if
00167   // there seem to be no more candidates
00168  # ifdef NOT_IMPLEMENTED
00169   int reclaimed = 0, iter = 0;
00170   while (iter++ < LRU_RETIREMENT_AGE && reclaimed < needed) {   
00171     int vis, recl;
00172     int limit = numberOfNMethods();             // because usedIDs may change
00173     int newTime = sweeper(limit, needed, &vis, &recl);
00174     reclaimed += recl;
00175     if (recl < needed && newTime > LRUtime + 1) {
00176       // next sweep wouldn't reclaim anything
00177       assert(vis == limit, "should have visited them all");
00178       LRUtime = newTime - 1;
00179       if (PrintLRUSweep) lprintf("\n*forced new LRU time: %ld", LRUtime);
00180     }
00181   }
00182   return reclaimed;
00183 #endif
00184   return 0;
00185 }
00186 
00187 // flush next replacement candidate; return # bytes freed
00188 int zone::flushNextMethod(int needed) {
00189   int freed = 0;
00190   Unimplemented();
00191   return freed;
00192 }
00193 
00194 void moveInsts(char* from, char* to, int size) {
00195   Unused(size);
00196   nmethod* n = (nmethod*) from;
00197   nmethod* nTo = (nmethod*)to;
00198   
00199   char* n1 = n->insts();
00200   char* n2 = n->instsEnd();
00201   n->moveTo(to, (char*)n->locsEnd() - (char*)n);
00202   if (Universe::code->LRUhand == n) Universe::code->LRUhand = nTo;
00203 }
00204 
00205 class ConvertBlockClosure : public ObjectClosure {
00206  public:
00207   void do_object(memOop obj) {
00208     if (obj->is_block() && blockClosureOop(obj)->isCompiledBlock()) {
00209       blockClosureOop(obj)->deoptimize();
00210     }
00211   }
00212 };
00213 
00214 void zone::flushZombies() {
00215   // 1. cleanup all methodOop inline caches
00216   // 2. cleanup all nmethod inline caches
00217   // 3..deoptimized blocks with compiled code.
00218 
00219   // Clear caches
00220   lookupCache::flush();
00221   // Universe::cleanup_all_inline_caches();
00222 
00223   Universe::flush_inline_caches_in_methods();
00224   clear_inline_caches();
00225 
00226   // Convert all blocks with compiled code
00227   ConvertBlockClosure bl;
00228   Universe::object_iterate(&bl);
00229 
00230   FOR_ALL_NMETHODS(p) {
00231     if (p->isZombie()) {
00232       p->flush();
00233     }
00234   }
00235 }
00236 
00237 void zone::flushUnused() {
00238   // flush all nmethods marked as unused
00239   // NB: access methods are always unused since they don't do the LRU thing
00240   // chainFrames();
00241   FOR_ALL_NMETHODS(p) {
00242     // use makeZombie() for efficiency, not flush()
00243     // (see comment in zone::flush())
00244     p->makeZombie(true);
00245   }
00246   flushZombies();
00247   flushICache();
00248   // unchainFrames();
00249 }
00250 
00251 void zone::adjustPolicy() {
00252   // This routine does the policy decisions about flushing, using feedback
00253   // from previous flushes.  If the heap is too full, then we'll soon have
00254   // to compact again, leading to frequent pauses and hight overhead.  On
00255   // the other hand, if we flush too many nmethods before compacting, we'll
00256   // have high compilation overhead to recreate the flushed code.
00257 # ifdef NOT_IMPLEMENTED
00258   if (DontUseAnyTimer) return;          // for reproducible results & debugging
00259   float timeSinceLast = cpuTimer->tickNo - compactTime;
00260   float overhead = compactDuration / timeSinceLast;
00261   if (overhead > COMPACT_OVERHEAD) {
00262     float currentFreeFrac = 1 - float(iZone->usedBytes()) / iZone->capacity();
00263     minFreeFrac = min(float(minFreeFrac * 1.5), float(minFreeFrac + 0.05));
00264     if (PrintCodeReclamation) {
00265       printf("(compact overhead %3.1f%%: increasing minFreeFrac to %3.1f%%) ",
00266              overhead *100, minFreeFrac * 100);
00267     }
00268   } else if (overhead < COMPACT_OVERHEAD / 2) {
00269     minFreeFrac = max(float(minFreeFrac / 1.5), float(minFreeFrac - 0.05));
00270     if (PrintCodeReclamation) {
00271       printf("(compact overhead %3.1f%%: decreasing minFreeFrac to %3.1f%%) ",
00272              overhead *100, minFreeFrac * 100);
00273     }
00274   }
00275   int minFree = int(iZone->capacity() * minFreeFrac);
00276   while (1) {
00277     int toFlush = minFree - (iZone->capacity() - iZone->usedBytes());
00278     if (toFlush <= 0) break;
00279     flushNextMethod(LRU_MAX_RECLAIMED);
00280   }
00281   compactTime = cpuTimer->tickNo;
00282 # endif
00283 }
00284 
00285 # define LRU_MAX_RECLAIMED 250000 /* stop after having found this amount of */
00286 # define LRUMaxVisited     150
00287 void zone::doSweep() { sweeper(LRUMaxVisited, LRU_MAX_RECLAIMED); }
00288 
00289 void zone::doWork() {
00290   if (needsSweep()) doSweep();
00291   if (needsCompaction()) compact();
00292 }
00293 
00294 void zone::compact(bool forced) {
00295   // BlockProfilerTicks bpt(exclude_nmethod_compact);
00296   // CSect cs(profilerSemaphore); // for profiler
00297 
00298   TraceTime t("*compacting nmethod cache...", PrintCodeReclamation);
00299   EventMarker em("compacting zone");
00300   
00301   // chainFrames();
00302   flushZombies();
00303   char* firstFree = NULL;
00304   if (!forced) adjustPolicy();
00305   if (needsCompaction()) {
00306     if (PrintCodeReclamation) std->print("I");
00307     firstFree = methodHeap->compact(moveInsts);
00308   }
00309   // unchainFrames();
00310   flushICache();
00311   
00312   verify_if_often();
00313   _needsCompaction = false;
00314   // compactDuration = cpuTimer->tickNo - compactTime;
00315 }
00316 
00317 void zone::free(nmethod* nm) {
00318   verify_if_often();
00319   if (LRUhand == nm) LRUhand = next_nm(nm);
00320   methodHeap->deallocate(nm, nm->size());
00321   verify_if_often();
00322 }
00323 
00324 void zone::addToCodeTable(nmethod* nm) {
00325   methodTable->add(nm);
00326 }
00327 
00328 void zone::clear_inline_caches() {
00329   TraceTime t("*flushing inline caches...", PrintInlineCacheInvalidation);
00330   EventMarker em("flushing inline caches");
00331 
00332   FOR_ALL_NMETHODS(p) {
00333     p->clear_inline_caches();
00334   }
00335 
00336   flushICache();
00337 }
00338 
00339 void zone::cleanup_inline_caches() {
00340   TraceTime t("*cleaning inline caches...", PrintInlineCacheInvalidation);
00341   EventMarker em("cleaning inline caches");
00342 
00343   FOR_ALL_NMETHODS(p) {
00344     p->cleanup_inline_caches();
00345   }
00346 
00347   flushICache();
00348 }
00349 
00350 inline int retirementAge(nmethod* n) {
00351   int delta = LRU_RETIREMENT_AGE;
00352   if (n->instsLen() <= LRU_CUTOFF)
00353     delta = max(delta, LRU_RETIREMENT_AGE * LRU_SMALL_BOOST);
00354   return n->lastUsed() + delta;
00355 }
00356 
00357 void zone::verify() {
00358   methodTable->verify();
00359   int n = 0;
00360   FOR_ALL_NMETHODS(p) {
00361     n++;
00362     p->verify();
00363   }
00364   if (n != numberOfNMethods())
00365     error("zone: inconsistent usedIDs value - should be %ld, is %ld",
00366            n, numberOfNMethods());
00367   methodHeap->verify();
00368   jump_table()->verify();
00369 }
00370 
00371 
00372 void zone::switch_pointers(oop from, oop to) { 
00373   Unimplemented();
00374 }
00375 
00376 void zone::oops_do(void f(oop*)) {
00377   FOR_ALL_NMETHODS(nm) {
00378     nm->oops_do(f);
00379   }
00380 
00381   FOR_ALL_PICS(pic) {
00382     pic->oops_do(f);
00383   }
00384 }
00385 
00386 void zone::nmethods_do(void f(nmethod* nm)) {
00387   FOR_ALL_NMETHODS(p) {
00388     f(p);
00389   }
00390 }
00391 
00392 void zone::PICs_do(void f(PIC* pic)) {
00393   FOR_ALL_PICS(p) {
00394     f(p);
00395   }
00396 }
00397 
00398 # define NMLINE(format, n, ntot, ntot2)                                       \
00399   std->print(format, (n), 100.0 * (n) / (ntot), 100.0 * (n) / (ntot2))
00400 
00401 class nmsizes {
00402   int n, insts, locs, scopes;
00403  public:
00404   nmsizes() {
00405     n = insts = locs = scopes = 0; }
00406 
00407   int total()   {
00408     return n * sizeof(nmethod)+ insts + locs + scopes; }
00409 
00410   bool isEmpty() { return n == 0; }
00411 
00412   void print(char* name, nmsizes& tot) {
00413     int bigTotal = tot.total();
00414     int myTotal = total();
00415     if (! isEmpty()) {
00416       std->print("%-13s (%ld methods): ", name, n);
00417       NMLINE("headers = %ld (%2.0f%%/%2.0f%%); ", n*sizeof(nmethod),
00418              myTotal, bigTotal);
00419       NMLINE("insts = %ld (%2.0f%%/%2.0f%%);\n", insts, myTotal, bigTotal);
00420       NMLINE("\tlocs = %ld (%2.0f%%/%2.0f%%); ", locs, myTotal, bigTotal);
00421       NMLINE("scopes = %ld (%2.0f%%/%2.0f%%);\n", scopes, myTotal, bigTotal);
00422       NMLINE("\ttotal = %ld (%2.0f%%/%2.0f%%)\n", myTotal, myTotal, bigTotal);
00423     }
00424   }
00425 
00426   void print(char* title, int t) {
00427     std->print_cr("   %3d %s nmethods %2d%% = %4dK (hdr %2d%%, inst %2d%%, locs %2d%%, debug %2d%%)",
00428                   n,
00429                   title,
00430                   total() * 100 / t,
00431                   total() / K,
00432                   n * sizeof(nmethod) * 100 / total(),
00433                   insts               * 100 / total(),
00434                   locs                * 100 / total(),
00435                   scopes              * 100 / total());
00436   }
00437 
00438   void add(nmethod* nm) {
00439     n++;
00440     insts  += nm->instsLen();
00441     locs   += nm->locsLen();
00442     scopes += nm->scopes()->length();
00443   }
00444 };
00445 
00446 void zone::print() {
00447   nmsizes nms;
00448   nmsizes zombies;
00449   int uncommon = 0;
00450 
00451   FOR_ALL_NMETHODS(p) {
00452     if (p->isZombie()) {
00453       zombies.add(p);
00454     } else {
00455       nms.add(p);
00456       if (p->isUncommonRecompiled()) uncommon++;
00457     }
00458   }
00459 
00460   std->print_cr("Zone:");
00461 
00462   if (!nms.isEmpty()) {
00463     std->print_cr("  Code (%dK, %d%% used)", methodHeap->capacity() / K, (methodHeap->usedBytes() * 100) / methodHeap->capacity());
00464     nms.print("live", methodHeap->capacity());
00465   }
00466   if (uncommon) {
00467     std->print_cr("(%d live uncommon nmethods)", uncommon);
00468   }
00469   if (!zombies.isEmpty()) {
00470     zombies.print("dead", methodHeap->capacity());
00471     std->print_cr("  PICs (%dK, %d%% used)", picHeap->capacity() / K, (picHeap->usedBytes() * 100) / picHeap->capacity());
00472   }
00473 
00474   int n     = 0;
00475   int insts = 0;
00476   FOR_ALL_PICS(pic) {
00477     n++;
00478     insts += pic->code_size();
00479   }
00480   int total = insts + n * sizeof(PIC);
00481 
00482   if (n > 0) {
00483     std->print_cr("   %3d entries = %dK (hdr %2d%%, inst %2d%%)",
00484                   n,
00485                   total / K,
00486                   n * sizeof(PIC) * 100 / total,
00487                   insts           * 100 / total);
00488   }
00489 }
00490 
00491 struct nm_hist_elem{
00492   nmethod* nm;
00493   int     count;
00494   int     size;
00495   int     sic_count;
00496   int     sic_size;
00497 };
00498 
00499 static int compareOop(const void *m1, const void *m2) {
00500   ResourceMark rm;
00501   struct nm_hist_elem *nmethod1 = (struct nm_hist_elem *) m1;
00502   struct nm_hist_elem *nmethod2 = (struct nm_hist_elem *) m2;
00503   return nmethod2->nm->method() - nmethod1->nm->method();
00504 }
00505 
00506 static int compareCount(const void *m1, const void *m2) {
00507   struct nm_hist_elem *nmethod1 = (struct nm_hist_elem *) m1;
00508   struct nm_hist_elem *nmethod2 = (struct nm_hist_elem *) m2;
00509   return nmethod2->count - nmethod1->count;
00510 }
00511 
00512 void zone::print_nmethod_histogram(int size) {
00513 # ifdef NOT_IMPLEMENTED
00514   ResourceMark rm;
00515   nm_hist_elem* hist_array = NEW_RESOURCE_ARRAY(nm_hist_elem, numberOfNMethods());
00516 
00517   int*  compiled_nmethods = NEW_RESOURCE_ARRAY(int, numberOfNMethods());
00518 
00519   int n = 0;
00520   FOR_ALL_NMETHODS(p) {
00521     if (!p->isAccess() && !p->isZombie()) {
00522       hist_array[n].nm     = p;
00523       hist_array[n].size   = p->instsLen() +
00524                              p->locsLen() +
00525                              p->depsLen +
00526                              p->scopes->length();
00527       n++;
00528     }
00529   }
00530 
00531   qsort(hist_array, n, sizeof(nm_hist_elem), compareOop);
00532   
00533   int i = 0;
00534   for (i = 0; i < n; i++) compiled_nmethods[i] = 0;
00535 
00536   i = 0;
00537   int out = 0;
00538   while (i < n) {
00539     int counter     = 1;
00540     int all_size    = 0;
00541     int sic_counter = 0;
00542     int sic_size    = 0;
00543 
00544     oop method = hist_array[i].nm->method();
00545     if (hist_array[i].nm->flags.compiler == nm_new) {
00546       sic_counter++;
00547       sic_size += hist_array[i].size;
00548     }
00549     all_size = hist_array[i].size;
00550 
00551     i++;
00552 
00553     while (i < n && method == hist_array[i].nm->method()) {
00554       if (hist_array[i].nm->flags.compiler == nm_sic) {
00555         sic_counter++;
00556         sic_size += hist_array[i].size;
00557       }
00558       all_size += hist_array[i].size;
00559       counter++; i++;
00560     }
00561     compiled_nmethods[counter]++;
00562     if (counter > size) {
00563       hist_array[out]           = hist_array[i-1];
00564       hist_array[out].count     = counter;
00565       hist_array[out].size      = all_size;
00566       hist_array[out].sic_count = sic_counter;
00567       hist_array[out].sic_size  = sic_size;
00568       out++;
00569     }
00570   }
00571 
00572   qsort(hist_array, out, sizeof(nm_hist_elem), compareCount);
00573 
00574   printf("\n# nm \t # methods \t%% acc.\n");
00575   int nm_count = 0;
00576   for (i = 0; i < n; i++) {
00577     if (compiled_nmethods[i] > 0) {
00578       nm_count += i * compiled_nmethods[i];
00579       printf("%5ld \t%5ld \t\t%3ld %%\n", i, compiled_nmethods[i], 
00580              (nm_count*100)/n);
00581 
00582     }
00583   }
00584 
00585   printf( "\nList of methods with more than %d nmethods compiled.\n", size);
00586   printf( " ALL(#,Kb)  Compiler(#,Kb) Method:\n");
00587   for (i = 0; i < out; i++) {
00588     printf("%4d,%-4d   %4d,%-4d ",
00589            hist_array[i].count,     hist_array[i].size / 1024,
00590            hist_array[i].sic_count, hist_array[i].sic_size / 1024);
00591     printName((methodKlass*) hist_array[i].nm->method()->klass(),
00592                hist_array[i].nm->key.selector);
00593     printf("\n");
00594   }
00595   
00596   fflush(stdout);
00597 # endif
00598 }
00599 
00600 bool zone::isDeltaPC(void* p) const {
00601   return methodHeap->contains(p)
00602       || picHeap->contains(p);
00603 }
00604 
00605 nmethod* zone::findNMethod(void* start) const {
00606   nmethod* n;
00607   if (methodHeap->contains(start)) {
00608     n = (nmethod*)methodHeap->findStartOfBlock(start);
00609     assert((char*)start < (char*)n->locsEnd(), "found wrong nmethod");
00610   }
00611   assert(methodHeap->contains(n), "not in zone");
00612   assert(n->isNMethod(), "findNMethod didn't find nmethod");
00613   assert(n->encompasses(start), "doesn't encompass start");
00614   return n;
00615 }
00616 
00617 
00618 nmethod* zone::findNMethod_maybe(void* start) const {
00619   // start *may* point into the instructions part of a nmethod; find it
00620   if (!methodHeap->contains(start)) return NULL;
00621   // relies on FOR_ALL_NMETHODS to enumerate in ascending order
00622   FOR_ALL_NMETHODS(p) {
00623     if (p->insts() > (char*)start) return NULL;
00624     if (p->instsEnd() > (char*)start) return p;
00625   }
00626   return NULL;
00627 }
00628 
00629 void zone::mark_dependents_for_deoptimization() {
00630   ResourceMark rm;
00631   FOR_ALL_NMETHODS(nm) {
00632     if (nm->depends_on_invalid_klass()) {
00633       GrowableArray<nmethod*>* nms = nm->invalidation_family();
00634       for (int index = 0; index < nms->length(); index++) {
00635         nmethod* elem = nms->at(index); 
00636         if (TraceApplyChange) {
00637           std->print("invalidating "); 
00638           elem->print_value_on(std);
00639           std->cr();
00640         }
00641         elem->mark_for_deoptimization();
00642       }
00643     }
00644   }
00645 }
00646 
00647 void zone::mark_all_for_deoptimization() {
00648   FOR_ALL_NMETHODS(nm) {
00649     nm->mark_for_deoptimization();
00650   }
00651 }
00652 
00653 void zone::unmark_all_for_deoptimization() {
00654   FOR_ALL_NMETHODS(nm) nm->unmark_for_deoptimization();
00655 }
00656 
00657 void zone::make_marked_nmethods_zombies() {
00658   FOR_ALL_NMETHODS(nm) {
00659     if (nm->is_marked_for_deoptimization()) {
00660       nm->makeZombie(true);
00661     }
00662   }
00663 }
00664 
00665 char* zone::instsStart() { return methodHeap->startAddr(); };
00666 int zone::instsSize()    { return methodHeap->capacity(); }
00667 
00668 inline nmethod* zone::next_circular_nm(nmethod* nm) {
00669   nm = next_nm(nm);
00670   if (nm == NULL) nm = first_nm();
00671   return nm;
00672 }
00673 
00674 // called every LRU_RESOLUTION seconds or by reclaimNMethods if needed
00675 // returns time at which oldest non-reclaimed nmethod will be reclaimed
00676 int zone::sweeper(int maxVisit, int maxReclaim,
00677                     int* nvisited, int* nbytesReclaimed) {
00678 # ifdef NOT_IMPLEMENTED
00679   EventMarker em("LRU sweep");
00680   ResourceMark rm;
00681 
00682   timer tmr;   
00683   int visited = 0;
00684   int nused = 0;
00685   int nbytes = 0;
00686   int nextTime = LRUtime + LRU_RETIREMENT_AGE;
00687   nmethod* first = first_nm();
00688   if (! first) return -1;
00689   
00690   nmethod* p = LRUhand ? LRUhand : first;
00691   if (PrintLRUSweep || PrintLRUSweep2) {
00692     printf("*starting LRU sweep...");
00693     fflush(stdout);
00694     tmr.start();
00695   }
00696     
00697   do {
00698     if (PrintLRUSweep2) printf("\n*inspecting %#lx (id %ld): ", p, p->id);
00699     
00700     if ((p->isZombie() ||
00701          p->isDebug()  ||
00702          p->codeTableLink.isEmpty() && !p->isUncommon()) &&
00703         p->frame_chain == NULL) {
00704       // can be flushed - nobody will ever use it again
00705       if (PrintLRUSweep2) printf(" %s; flushed",
00706                                  p->isZombie() ? "zombie" :
00707                                  (p->isDebug() ? "debug" : "unreachable"));
00708       nbytes += iZone->sizeOfBlock(p);
00709       p->flush();
00710     } else if (p->isUsed()) {
00711       // has been used
00712       nused++;
00713       if (PrintLRUSweep2) {
00714         printf("used");
00715         int diff = useCount[p->id] - p->oldCount;
00716         if (diff) printf(" %ld times", diff);
00717       }
00718       if (LRUDecayFactor > 1) {
00719         useCount[p->id] = int(useCount[p->id] / LRUDecayFactor);
00720       }
00721       p->oldCount = useCount[p->id];
00722       LRUtable[p->id].unused = true;
00723       LRUtable[p->id].lastUsed = LRUtime;
00724       if (p->zoneLink.notEmpty()) {
00725         if (PrintLRUSweep2) printf("; removed from replCandidates");
00726         p->zoneLink.remove();           // no longer a replacement candidate
00727         nbytes -= iZone->sizeOfBlock(p);
00728       }
00729     } else if (retirementAge(p) < LRUtime && p->zoneLink.isEmpty()) {
00730       if (PrintLRUSweep2) printf("added to replCandidates");
00731       replCandidates.add(&p->zoneLink);
00732       nbytes += iZone->sizeOfBlock(p);
00733     } else {
00734       int age = retirementAge(p);
00735       if (age < nextTime) {
00736         nextTime = age;
00737       }
00738       if (PrintLRUSweep2) {
00739         printf("unused (age %ld)", LRUtime - p->lastUsed());
00740         if (p->zoneLink.notEmpty())
00741           printf(" already scheduled for replacement");
00742       }
00743     }
00744     
00745     nmethod* oldp = p;
00746     p = next_circular_nm(p);
00747     if (p < oldp) {                             // wrap around
00748       LRUtime++;
00749       // The LRU scheme will actually fail if LRUtime > 2^16, but that
00750       // won't happen very often (every 20*LRU_RESOLUTION CPU hours).
00751       if (PrintLRUSweep2) printf("\n*new LRU time: %ld", LRUtime);
00752     }
00753   } while (++visited < maxVisit && nbytes < maxReclaim && p);
00754   
00755   if (needsSweep() && LRUDecayFactor > 1) {
00756     // called from timer; decay count stubs
00757     stubs->decay(LRUDecayFactor);
00758   }
00759   
00760   LRUhand = p;
00761   _needsSweep = false;
00762   if (PrintLRUSweep || PrintLRUSweep2) {
00763     printf(" done: %ld/%ld visits, %ld bytes, %ld ms.\n",
00764            nused, visited, nbytes, tmr.time());
00765     fflush(stdout);
00766   }
00767   if (nvisited) *nvisited = visited;
00768   if (nbytesReclaimed) *nbytesReclaimed = nbytes;
00769   return nextTime;
00770 # endif
00771   return 0;
00772 }
00773 
00774 int zone::LRU_time() { return LRUtime; }
00775 
00776 void printAllNMethods() {
00777   for(nmethod* m = Universe::code->first_nm(); m != NULL; m = Universe::code->next_nm(m)) {
00778     if (!m->isZombie()) {
00779       m->scopes()->print_partition();
00780     }
00781   }
00782 }
00783 
00784 #endif

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