nmethod.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.114 $ */
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/_nmethod.cpp.incl"
00029 
00030 
00031 void nmFlags::clear() {
00032   assert(sizeof(nmFlags) == sizeof(int), "using more than one word for nmFlags");
00033   *(int*)this = 0;
00034 }
00035 
00036 
00037 static int instruction_length;
00038 static int location_length;
00039 static int scope_length;
00040 static int nof_noninlined_blocks;
00041 
00042 
00043 nmethod* new_nmethod(Compiler* c) {
00044   // This grossness is brought to you by the great way in which C++
00045   // handles non-standard allocation...
00046   instruction_length    = roundTo(c->code()->code_size(),         oopSize);
00047   location_length       = roundTo(c->code()->reloc_size(),        oopSize);
00048   scope_length          = roundTo(c->scopeDescRecorder()->size(), oopSize);
00049   nof_noninlined_blocks = c->number_of_noninlined_blocks();
00050   nmethod* nm = new nmethod(c);
00051   if (c->is_method_compile()) {
00052     Universe::code->addToCodeTable(nm);
00053   }
00054   return nm;
00055 }
00056 
00057 
00058 void* nmethod::operator new(size_t size) {
00059   Unused(size);
00060   assert(sizeof(nmethod) % oopSize == 0, "nmethod size must be multiple of a word");
00061   int nmethod_size = sizeof(nmethod) 
00062                    + instruction_length
00063                    + location_length
00064                    + scope_length
00065                    + roundTo((nof_noninlined_blocks) * sizeof(uint16), oopSize);
00066   void *p = Universe::code->allocate(nmethod_size);
00067   if (!p) fatal("out of space in code cache");
00068   return p;
00069 }
00070 
00071 
00072 nmethod::nmethod(Compiler* c) : key(c->key->klass(), c->key->selector_or_method()) {
00073 #ifdef ASSERT
00074   // lookupCache::verify();
00075 #endif
00076   // Initializing the chunks sizes
00077   _instsLen     = instruction_length;
00078   _locsLen      = location_length; 
00079   _scopeLen     = scope_length;
00080 
00081   main_id       = c->main_jumpTable_id;
00082   promoted_id   = c->promoted_jumpTable_id;
00083 
00084   _number_of_noninlined_blocks = nof_noninlined_blocks;
00085 
00086   _invocation_count             = 0;
00087   _uncommon_trap_counter        = 0;
00088   _number_of_links              = 0;
00089 
00090   _special_handler_call_offset  = theCompiler->special_handler_call_offset();
00091   _entry_point_offset           = theCompiler->entry_point_offset();
00092   _verified_entry_point_offset  = theCompiler->verified_entry_point_offset();
00093   assert(_entry_point_offset          % oopSize == 0, "entry point is not aligned");
00094   assert(_verified_entry_point_offset % oopSize == 0, "verified entry point is not aligned");
00095   assert(0 <= _special_handler_call_offset && _special_handler_call_offset < instruction_length, "bad special handler call offset");
00096   assert(0 <= _entry_point_offset          && _entry_point_offset          < instruction_length, "bad entry point offset");
00097   assert(0 <= _verified_entry_point_offset && _verified_entry_point_offset < instruction_length, "bad verified entry point offset");
00098 
00099   _number_of_float_temporaries  = theCompiler->totalNofFloatTemporaries();
00100   _float_section_size           = theCompiler->float_section_size();
00101   _float_section_start_offset   = theCompiler->float_section_start_offset();
00102   
00103   flags.clear();
00104   flags.isUncommonRecompiled = c->is_uncommon_compile();
00105       
00106   flags.level    = c->level();
00107   flags.version  = c->version();
00108   flags.is_block = c->is_block_compile() ? 1 : 0;
00109 
00110   flags.state    = alive;
00111 
00112   if (UseNMethodAging) makeYoung();
00113 
00114   // assert(c->frameSize() >= 0, "frame size cannot be negative");
00115   // frame_size = c->frameSize();
00116 
00117   // Fill in instructions and locations.
00118   c->code()->copyTo(this);
00119   // Fill in scope information
00120   c->scopeDescRecorder()->copyTo(this);
00121   // Fill in noninlined block scope table
00122   c->copy_noninlined_block_info(this);
00123 
00124   flushICacheRange(insts(), instsEnd());
00125   flushICache();
00126 
00127 #ifdef ASSERT
00128   check_store();
00129 #endif
00130 
00131   // Set the jumptable entry for the nmethod
00132   if (c->is_method_compile()) {
00133     Universe::code->jump_table()->at(main_id)->set_destination(entryPoint());
00134   } else {
00135     if (has_noninlined_blocks()) {
00136       Universe::code->jump_table()->at(promoted_id)->set_destination(entryPoint());
00137     }
00138   }
00139   if (this == (nmethod*)catchThisOne) warning("caught nmethod");
00140 #ifdef ASSERT
00141   // turned off because they're very slow  -Urs 4/96
00142   // lookupCache::verify();
00143   verify_expression_stacks();
00144 #endif
00145 }
00146 
00147 
00148 nmethod* nmethod::parent() {
00149   if (is_block()) {
00150     int index;
00151     return Universe::code->jump_table()->at(main_id)->parent_nmethod(index);
00152   }
00153   return NULL;
00154 }
00155 
00156 
00157 nmethod* nmethod::outermost() {
00158   nmethod* p = parent();
00159   if (p == NULL) return this;
00160   return p->outermost();
00161 }
00162 
00163 
00164 int nmethod::level() const {
00165   assert(flags.level >= 0 && flags.level <= MaxRecompilationLevels,
00166          "invalid level");
00167   return flags.level;
00168 }
00169 
00170 
00171 jumpTableEntry* nmethod::jump_table_entry() const {
00172   return Universe::code->jump_table()->at(main_id);
00173 }
00174 
00175 
00176 void nmethod::setVersion(int v) {
00177   assert(v > 0 && v <= MaxVersions, "bad version");
00178   flags.version = v;
00179 }
00180 
00181 
00182 ScopeDesc* nmethod::containingScopeDesc(char* pc) const {
00183   PcDesc* pcd = containingPcDesc(pc);
00184   if (!pcd) return NULL;
00185   return pcd->containingDesc(this);
00186 }
00187 
00188 
00189 void nmethod::check_store() {
00190   // Make sure all oops in the compiled code are tenured
00191   relocIterator iter(this);
00192   while (iter.next()) {
00193     if (iter.type() == relocInfo::oop_type) {
00194       oop obj = *iter.oop_addr();
00195       if (obj->is_mem() && obj->is_new()) {
00196         fatal("must be tenured oop in compiled code");
00197       }
00198     }
00199   }
00200 }
00201 
00202 
00203 void nmethod::fix_relocation_at_move(int delta) {
00204   relocIterator iter(this);
00205   while (iter.next()) {
00206     if (iter.is_position_dependent()) {
00207       if (iter.type() == relocInfo::internal_word_type) {
00208         *iter.word_addr() -= delta;
00209       } else {
00210         *iter.word_addr() += delta;
00211       }
00212     }
00213   }
00214 }
00215 
00216 
00217 methodOop nmethod::method() const {
00218   ResourceMark rm;
00219   return scopes()->root()->method();
00220 }
00221 
00222 
00223 klassOop nmethod::receiver_klass() const {
00224   ResourceMark rm;
00225   return scopes()->root()->selfKlass();
00226 }
00227 
00228 
00229 void nmethod::moveTo(void* p, int size) {
00230 # ifdef NOT_IMPLEMENTED
00231   nmethod* to = (nmethod*)p;
00232   if (this == to) return;
00233   if (PrintCodeCompaction) {
00234     printf("*moving nmethod %#lx (", this);
00235     key.print();
00236     printf(") to %#lx\n", to);
00237     fflush(stdout);
00238   }
00239 
00240   assert(iabs((char*)to - (char*)this) >= sizeof(NCodeBase),
00241          "nmethods overlap too much");
00242   assert(sizeof(NCodeBase) % oopSize == 0, "should be word-aligned");
00243   copy_oops((oop*)this, (oop*)to, sizeof(NCodeBase) / oopSize);
00244                 // init to's vtable
00245   int delta = (char*) to - (char*) this;
00246       
00247   for (relocInfo* q = locs(), *pend = locsEnd(); q < pend; q++) {
00248     bool needShift;             // speed optimization - q->shift() is slow
00249     if (q->isIC()) {
00250       IC* sd = q->asIC(this);
00251       sd->shift(delta, this);
00252       needShift = true;
00253     } else {
00254       needShift = true;
00255     }      
00256     if (needShift) {
00257       q->shift(this, delta);
00258     }
00259   }
00260 
00261   assert(size % oopSize == 0, "not a multiple of oopSize");
00262   copy_oops_overlapping((oop*) this, (oop*) to, size / oopSize);
00263   flushICacheRange(to->insts(), to->instsEnd());
00264 # endif
00265 }
00266 
00267 
00268 void nmethod::clear_inline_caches() {
00269   // Iterate over all inline caches and flush them
00270   relocIterator iter(this);
00271   while (iter.next()) {
00272     if (iter.type() == relocInfo::ic_type) {
00273       iter.ic()->clear();
00274     }
00275   }
00276 }
00277 
00278 
00279 void nmethod::cleanup_inline_caches() {
00280   // Ignore zombies
00281   if (isZombie()) return;
00282 
00283   // Iterate over all inline caches and flush them
00284   relocIterator iter(this);
00285   while (iter.next()) {
00286     if (iter.type() == relocInfo::ic_type) {
00287       iter.ic()->cleanup();
00288     }
00289   }
00290 }
00291 
00292 
00293 void nmethod::makeOld() {
00294   LOG_EVENT1("marking nmethod %#x as old", this);
00295   flags.isYoung = 0;
00296 }
00297 
00298 
00299 void nmethod::forwardLinkedSends(nmethod* to) {
00300   // the to nmethod is about to replace the receiver; replace receiver in
00301   // all inline caches
00302   Unimplemented();
00303 }
00304 
00305 
00306 void nmethod::unlink() {
00307   LOG_EVENT1("unlinking nmethod %#lx", this);
00308 
00309   if (is_method()) {
00310     // Remove from lookupCache.
00311     lookupCache::flush(&key);
00312     // Remove the nmethod from the code table.if it's still there (another nmethod with the
00313     // same key may have been added in the meantime).
00314     if (Universe::code->methodTable->is_present(this)) Universe::code->methodTable->remove(this);
00315   }
00316 
00317   // Now clear all inline caches filled with this nmethod
00318   // (*not* done by clear_inline_caches() -- that clears the inline caches *in* this nmethod).
00319   // Right now, can't do this -- don't know who is calling this nmethod.
00320 }
00321 
00322 
00323 void nmethod::makeZombie(bool clearInlineCaches) {
00324   // mark this nmethod as zombie (it is almost dead and can be flushed as
00325   // soon as it is no longer on the stack)
00326   if (isZombie()) return;
00327 
00328   // overwrite call to recompiler by call to zombie handler
00329   LOG_EVENT2("%s nmethod 0x%x becomes zombie", (is_method() ? "normal" : "block"), this);
00330   NativeCall* call = nativeCall_at(specialHandlerCall());
00331 
00332   // Fix this:
00333   //   CODE NEEDED UNTIL Lars IMPLEMENTS CORRECT DEOPTIMIZATION FOR BLOCK NMETHODS
00334   if (is_block() && !MakeBlockMethodZombies) return;
00335 
00336   if (is_method()) {
00337     call->set_destination(StubRoutines::zombie_nmethod_entry());
00338   } else {
00339     call->set_destination(StubRoutines::zombie_block_nmethod_entry());
00340   }
00341 
00342   // WARNING: INTEL SPECIFIC CODE PROVIDED BY ROBERT
00343   // at verified entry point: overwrite "push ebp, mov ebp esp" instructions
00344   // belonging to activation frame construction with jump to zombie handler
00345   // call (note that this code can be savely overwritten, since there's no
00346   // relocation info nor oops associated with it).
00347   const char* enter = "\x55\x8b\xec";
00348   char* p = verifiedEntryPoint();
00349   guarantee(p[0] == enter[0] && p[1] == enter[1] && p[2] == enter[2], "not \"push ebp, mov ebp esp\" - check this");
00350   // overwrite with "nop, jmp specialHandlerCall" (nop first so it can be replaced by int3 for debugging)
00351   const char nop = '\x90';
00352   const char jmp = '\xeb'; // short jump with 8bit signed offset
00353   int offset = specialHandlerCall() - &p[3];
00354   guarantee(-128 <= offset && offset < 128, "offset too big for short jump");
00355   p[0] = nop;
00356   p[1] = jmp;
00357   p[2] = char(offset);
00358 
00359   if (TraceZombieCreation) {
00360     std->print_cr("%s nmethod 0x%x becomes zombie", (is_method() ? "normal" : "block"), this);
00361     if (WizardMode) {
00362       std->print_cr("entry code sequence:");
00363       char* beg = (char*)min(int(specialHandlerCall()), int(entryPoint()), int(verifiedEntryPoint()));
00364       char* end = (char*)max(int(specialHandlerCall()), int(entryPoint()), int(verifiedEntryPoint()));
00365       Disassembler::decode(beg, end + 10);
00366     }
00367   }
00368 
00369   // Update flags
00370   flags.state = zombie;
00371   flags.isToBeRecompiled = 0;
00372   assert(isZombie(), "just checking");
00373  
00374   // Make sure the entry is gone from the lookup cache & inline caches
00375   lookupCache::flush(&key);
00376   if (clearInlineCaches) clear_inline_caches();
00377 
00378   // Remove from nmethod tables
00379   unlink();
00380 }
00381 
00382 
00383 bool nmethod::has_noninlined_blocks() const {
00384   return number_of_noninlined_blocks() > 0;
00385 }
00386 
00387 
00388 int nmethod::number_of_noninlined_blocks() const {
00389   return _number_of_noninlined_blocks;
00390 }
00391 
00392 
00393 methodOop nmethod::noninlined_block_method_at(int noninlined_block_index) const {
00394   ResourceMark rm;
00395   return noninlined_block_scope_at(noninlined_block_index)->method();
00396 }
00397 
00398 
00399 inline void nmethod::validate_noninlined_block_scope_index(int index) const {
00400   assert(index > 0, 
00401          "noninlined_block_index must be positive");
00402   assert(index <= number_of_noninlined_blocks(), 
00403          "noninlined_block_index must be within boundary");
00404 }
00405 
00406 
00407 NonInlinedBlockScopeDesc* nmethod::noninlined_block_scope_at(int noninlined_block_index) const {
00408   validate_noninlined_block_scope_index(noninlined_block_index);
00409   int offset = noninlined_block_offsets()[noninlined_block_index-1];
00410   return scopes()->noninlined_block_scope_at(offset);
00411 }
00412 
00413 
00414 void nmethod::noninlined_block_at_put(int noninlined_block_index, int offset) const {
00415   validate_noninlined_block_scope_index(noninlined_block_index);
00416   noninlined_block_offsets()[noninlined_block_index-1] = offset;
00417 }
00418 
00419 jumpTableEntry* nmethod::noninlined_block_jumpEntry_at(int noninlined_block_index) const {
00420   validate_noninlined_block_scope_index(noninlined_block_index);
00421   jumpTableID id = is_block() ? promoted_id : main_id;
00422   return Universe::code->jump_table()->at(id.sub(noninlined_block_index));
00423 }
00424 
00425 void nmethod::flush() {
00426   // completely deallocate this method
00427   EventMarker em("flushing nmethod %#lx %s", this, "");
00428   if (PrintMethodFlushing) {
00429     std->print_cr("*flushing nmethod %#lx", this);
00430   }
00431   if (isZombie()) {
00432     clear_inline_caches();    // make sure they're cleared (may not have been done by makeZombie)
00433   } else {
00434     makeZombie(true);
00435   }
00436   unlink();
00437   Universe::code->free(this);
00438 }
00439 
00440 
00441 bool nmethod::depends_on_invalid_klass() {
00442   // Check receiver class
00443   if (receiver_klass()->is_invalid())
00444     return true;
00445 
00446   // Check dependents
00447   nmethodScopes* ns = scopes();
00448   for (int index = ns->dependent_length()-1; index >= 0; index--) {
00449     if (ns->dependant_at(index)->is_invalid()) 
00450       return true;
00451   }
00452 
00453   // We do not depend on an invalid class
00454   return false;
00455 }
00456 
00457 
00458 void nmethod::add_family(GrowableArray<nmethod*>* result) {
00459   // Add myself
00460   result->append(this);
00461   // Find the major for all my sub jumpTable entries
00462   int major = is_method() ? main_id.major() : promoted_id.major();
00463   // Add all filled jumpTable entries to the family
00464   for (int minor = 1; minor <= number_of_noninlined_blocks(); minor++) {
00465     jumpTableEntry* entry = Universe::code->jump_table()->at(jumpTableID(major, minor));
00466     nmethod* bm = entry->block_nmethod();
00467     if (bm) bm->add_family(result);
00468   }
00469 }
00470 
00471 
00472 GrowableArray<nmethod*>* nmethod::invalidation_family() {
00473   GrowableArray<nmethod*>* result = new GrowableArray<nmethod*>(10);
00474   add_family(result); // Call the recusive function
00475   return result;
00476 }
00477 
00478 
00479 PcDesc* nmethod::containingPcDescOrNULL(char* pc, PcDesc* st) const {
00480   // returns PcDesc that is closest one before or == to pc, or NULL if
00481   // no stored pcDesc exists 
00482   // called a lot, so watch out for performance bugs
00483   assert(contains(pc), "nmethod must contain pc into frame");
00484   int offset = pc - insts();
00485   PcDesc* start = st ? st : pcs();
00486   PcDesc* end = pcsEnd() - 1;
00487 
00488   // Skim the cream if only one pcDesc is present.
00489   if (start == end) return start; 
00490 
00491   assert(start <= end, "no PcDescs to search");
00492 
00493   // binary search to find approx. location
00494   PcDesc* middle;
00495   int l = 0, h = end - start;
00496   do {
00497     // avoid pointer arithmetic -- gcc uses a division for PcDesc* - PcDesc*
00498     int m = l + (h - l) / 2;
00499     middle = &start[m];
00500     if (middle->pc < offset) {
00501       l = m + 1;
00502     } else {
00503       h = m - 1;
00504     }
00505   } while (middle->pc != offset && l < h);
00506 
00507   // may not have found exact offset, so search for closest match
00508   while (middle->pc <= offset && middle < end  ) middle++;
00509   while (middle->pc >  offset && middle > start) middle--;
00510   
00511   assert(start <= middle && middle <= end, "should have found a pcDesc");
00512 # ifdef ASSERT
00513     PcDesc* d = st ? st : pcs();
00514     PcDesc* closest = d;
00515     for (; d <= end; d ++) {
00516       if (d->pc <= offset && (closest == NULL || closest->pc <= d->pc)) {
00517         closest = d;
00518       }
00519     }
00520     assert(closest == middle, "found different pcDesc");
00521 # endif
00522 
00523   if (middle->pc > offset) {
00524     assert( middle == start, "should be the first PcDesc");
00525     // in prologue; caller has to deal with this
00526     return NULL;
00527   }
00528   return middle;
00529 }
00530 
00531 
00532 // Create a static PcDesc for prologue PcDesc's
00533 static PcDesc prologue_pd(0, 0, PrologueBCI);
00534 
00535 PcDesc* nmethod::containingPcDesc(char* pc, PcDesc* start) const {
00536   // returns PcDesc that is closest one before or == to pc
00537   PcDesc* p = containingPcDescOrNULL(pc, start);
00538   // in prologue; there is no PcDesc stored in the nmethod (to save space),
00539   // so we have to create one
00540   return p ? p : &prologue_pd;
00541 }
00542 
00543 
00544 int nmethod::estimatedInvocationCount() const {
00545   Unimplemented();
00546   return 0;
00547 }
00548 
00549 
00550 static int cmp_addrs(const void* p1,  const void* p2) {
00551   char** r1 = (char**) p1;
00552   char** r2 = (char**) p2;
00553   return *r1 - *r2;
00554 }
00555 
00556 
00557 int nmethod::ncallers() const {
00558   return number_of_links();
00559 }
00560 
00561 
00562 // Memory operations: return true if need to inval cache
00563 
00564 void nmethod::relocate() {
00565   key.relocate();
00566   scopes()->relocate();
00567   OopNCode::relocate();
00568 }
00569 
00570 
00571 bool nmethod::switch_pointers(oop from, oop to,
00572                               GrowableArray<nmethod*>* nmethods_to_invalidate) {
00573   key.switch_pointers(from, to);
00574   scopes()->switch_pointers(from, to, nmethods_to_invalidate);
00575   check_store();
00576   return OopNCode::switch_pointers(from, to, nmethods_to_invalidate);
00577 }
00578 
00579 
00580 void nmethod::oops_do(void f(oop*)) {
00581   // LookupKey
00582   key.oops_do(f);
00583 
00584   // Compiled code
00585   relocIterator iter(this);
00586   while (iter.next()) {
00587     if (iter.type() == relocInfo::oop_type) {
00588       f(iter.oop_addr());
00589     }
00590    }
00591 
00592   // Debugging information
00593   scopes()->oops_do(f);
00594 }
00595 
00596 
00597 void nmethod::verify() {
00598   ResourceMark rm;
00599 
00600   OopNCode::verify2("nmethod");
00601 
00602   // Make sure all entry points are aligned
00603   // The interpreter counts on it for InterpreterPICs
00604 
00605   if (!oop(insts())->is_smi())
00606     error("nmethod at %#lx has unaligned instruction start", this);
00607 
00608   if (!oop(entryPoint())->is_smi())
00609     error("nmethod at %#lx has unaligned entryPoint", this);
00610     
00611   if (!oop(verifiedEntryPoint())->is_smi())
00612     error("nmethod at %#lx has unaligned verifiedEntryPoint", this);
00613 
00614   if (!Universe::code->contains(this))
00615     error("nmethod at %#lx not in zone", this);
00616       
00617   scopes()->verify();
00618 
00619   for (PcDesc* p = pcs(); p < pcsEnd(); p++) {
00620     if (! p->verify(this)) {
00621       std->print_cr("\t\tin nmethod at %#lx (pcs)", this);
00622     }
00623   }
00624   
00625   if (findNMethod((char*) instsEnd() - oopSize) != this) {
00626     error("findNMethod did not find this nmethod (%#lx)", this);
00627   }
00628 
00629   verify_expression_stacks();
00630 }
00631 
00632 
00633 void nmethod::verify_expression_stacks_at(char* pc) {
00634   PcDesc* pd = containingPcDesc(pc);
00635   if (!pd) fatal("PcDesc not found");
00636 
00637   ScopeDesc* sd  = scopes()->at(pd->scope, pc);
00638   int        bci = pd->byteCode;
00639   while (sd) {
00640     sd->verify_expression_stack(bci);
00641     ScopeDesc* next = sd->sender();
00642     if (next) bci = sd->senderBCI();
00643     sd  = next;
00644   }
00645 }
00646 
00647 
00648 void nmethod::verify_expression_stacks() {
00649   relocIterator iter(this);
00650   while (iter.next()) {
00651     switch (iter.type()) {
00652       case relocInfo::ic_type:
00653         verify_expression_stacks_at(iter.ic()->begin_addr());
00654         break;
00655       case relocInfo::prim_type:
00656         if (iter.primIC()->primitive()->can_walk_stack()) {
00657           verify_expression_stacks_at(iter.primIC()->begin_addr());
00658         }
00659         break;
00660     }
00661   }
00662 }
00663 
00664 
00665 void nmethod::CompiledICs_do(void f(CompiledIC*)) {
00666   relocIterator iter(this);
00667   while (iter.next())
00668     if (iter.type() == relocInfo::ic_type)
00669       f(iter.ic());
00670 }
00671 
00672 
00673 void nmethod::PrimitiveICs_do(void f(PrimitiveIC*)) {
00674   relocIterator iter(this);
00675   while (iter.next())
00676     if (iter.type() == relocInfo::prim_type)
00677       f(iter.primIC());
00678 }
00679 
00680 
00681 // Printing operations
00682 
00683 void nmethod::print() {
00684   ResourceMark rm;
00685   printIndent();
00686   std->print("((nmethod*)%#lx) ", this);
00687   std->print(" for method %#lx ", method());
00688   key.print();
00689   std->print(" { ");
00690   if (isYoung()) std->print("YOUNG ");
00691   if (version()) std->print("v%d ", version());
00692   if (level()) std->print("l%d ", level());
00693   if (isZombie()) std->print("zombie ");
00694   if (isToBeRecompiled()) std->print("TBR ");
00695   if (isUncommonRecompiled()) std->print("UNCOMMON ");
00696   std->print_cr("}:");
00697   Indent ++;   
00698       
00699   printIndent();
00700   std->print_cr("instructions (%ld bytes): [%#lx..%#lx]", size(), insts(), instsEnd());
00701   printIndent();
00702   std->print_cr("((nmethod*)%#lx)->printCode()", this);
00703   // don't print code/locs/pcs by default -- too much output   -Urs 1/95
00704   // printCode();
00705   scopes()->print();
00706   // printLocs();
00707   // printPcs();
00708   Indent --;
00709 }
00710 
00711 
00712 void nmethod::printCode() {
00713   ResourceMark m;
00714   Disassembler().decode(this);
00715 }
00716 
00717 
00718 void nmethod::printLocs() {
00719   ResourceMark m;       // in case methods get printed via the debugger
00720   printIndent();
00721   std->print_cr("locations:");
00722   Indent ++;
00723   relocIterator iter(this);
00724   int last_offset = 0;
00725   for (relocInfo* l = locs(); l < locsEnd(); l++) {
00726     iter.next();
00727     last_offset = l->print(this, last_offset);
00728     if (iter.type() == relocInfo::uncommon_type && iter.wasUncommonTrapExecuted()) std->print(" (taken)");
00729     std->cr();
00730   }
00731   Indent --;
00732 }
00733 
00734 
00735 void nmethod::printPcs() {
00736   ResourceMark m;       // in case methods get printed via debugger
00737   printIndent();
00738   lprintf("pc-bytecode offsets:\n");
00739   Indent ++;
00740   for (PcDesc* p = pcs(); p < pcsEnd(); p ++) p->print(this);
00741   Indent --;
00742 }
00743 
00744 
00745 void nmethod::print_value_on(outputStream* st) {
00746   st->print("nmethod");
00747   if (WizardMode) st->print(" (0x%lx)", this);
00748   st->print(":");
00749   method()->print_value_for(receiver_klass(), st);
00750 }
00751 
00752 
00753 static ScopeDesc* print_scope_node(nmethodScopes* scopes, ScopeDesc* sd, int level, outputStream* st, bool with_debug_info) {
00754   // indent
00755   st->fill_to(2 + level*2);
00756 
00757   // print scope
00758   sd->print_value_on(st);
00759   st->cr();
00760   if (with_debug_info) sd->print(4 + level*2, UseNewBackend);
00761 
00762   // print sons
00763   ScopeDesc* son = scopes->getNext(sd);
00764   while (son && son->sender_scope_offset() == sd->offset()) {
00765     son = print_scope_node(scopes, son, level+1, st, with_debug_info);
00766   }
00767   return son;
00768 }
00769 
00770 
00771 void nmethod::print_inlining(outputStream* st, bool with_debug_info) {
00772   // Takes advantage of the fact that the scope tree is stored in a depth first traversal order.
00773   ResourceMark rm;
00774   if (st == NULL) st = std;
00775   st->print_cr("nmethod inlining structure");
00776   ScopeDesc* result = print_scope_node(scopes(), scopes()->root(), 0, st, with_debug_info);
00777   if (result != NULL) warning("print_inlining returned prematurely");
00778 }
00779 
00780 
00781 nmethod* nmethodContaining(char* pc, char* likelyEntryPoint) {
00782   assert(Universe::code->contains(pc), "should contain address");
00783   if (likelyEntryPoint && Universe::code->contains(likelyEntryPoint)) {
00784     nmethod* result = nmethod_from_insts(likelyEntryPoint);
00785     if (result->contains(pc)) return result;
00786   }
00787   return findNMethod(pc);
00788 }
00789 
00790 
00791 nmethod* findNMethod(void* start) {
00792   nmethod* m = Universe::code->findNMethod(start);
00793   assert(m->encompasses(start), "returned wrong nmethod");
00794   return m;
00795 }
00796 
00797 
00798 nmethod* findNMethod_maybe(void* start) {
00799   nmethod* m = Universe::code->findNMethod_maybe(start);
00800   assert(!m || m->encompasses(start), "returned wrong nmethod");
00801   return m;
00802 }
00803 
00804 
00805 inline bool includes(void* p, void* from, void* to) {
00806   return from <= p && p < to;
00807 }
00808 
00809 
00810 bool nmethod::encompasses(void* p) const {
00811   return includes(p, (void*)this, pcsEnd());
00812 }
00813 
00814 
00815 #ifdef DEBUG_LATER
00816 PcDesc* nmethod::correspondingPC(ScopeDesc* sd, int bci) {
00817   // find the starting PC of this scope
00818   assert(scopes()->includes(sd), "scope not in this nmethod");  
00819   int scope = scopes()->offsetTo(sd);
00820   for (PcDesc* p = pcs(), *end = pcsEnd(); p < end; p ++) {
00821     if (p->scope == scope && p->byteCode == bci) break;
00822   }
00823   if (p < end ) {
00824     return p;
00825   } else {
00826     // no PC corresponding to this scope
00827     return NULL;
00828   }
00829 }
00830 #endif
00831 
00832 
00833 CompiledIC* nmethod::IC_at(char* p) const {
00834   relocIterator iter(this);
00835   while (iter.next())
00836     if (iter.type() == relocInfo::ic_type)
00837       if (iter.ic()->begin_addr() == p) return iter.ic();
00838   return NULL;
00839 }
00840 
00841 
00842 PrimitiveIC* nmethod::primitiveIC_at(char* p) const {
00843   relocIterator iter(this);
00844   while (iter.next())
00845     if (iter.type() == relocInfo::prim_type)
00846       if (iter.primIC()->begin_addr() == p) return iter.primIC();
00847   return NULL;
00848 }
00849 
00850 
00851 oop* nmethod::embeddedOop_at(char* p) const {
00852   relocIterator iter(this);
00853   while (iter.next())
00854     if (iter.type() == relocInfo::oop_type)
00855       if (iter.oop_addr() == (oop*) p) return iter.oop_addr();
00856   return NULL;
00857 }
00858 
00859 
00860 bool nmethod::in_delta_code_at(char* pc) const {
00861   PcDesc* pd = containingPcDescOrNULL(pc);
00862   if (pd == NULL) return false;
00863   return !(pd->byteCode == PrologueBCI || pd->byteCode == EpilogueBCI);
00864 }
00865 
00866 
00867 // Support for preemption:
00868 
00869 void nmethod::overwrite_for_trapping(nmethod_patch* data) {
00870   relocIterator iter(this);
00871   while (iter.next()) {
00872     switch(iter.type()) {
00873       case relocInfo::ic_type:           break;
00874       case relocInfo::prim_type:         break;
00875       case relocInfo::runtime_call_type: break;
00876       case relocInfo::uncommon_type:     break;
00877     }
00878   }
00879 }
00880 
00881 
00882 void nmethod::restore_from_patch(nmethod_patch* data) {
00883   Unimplemented();
00884 }
00885 
00886 
00887 void nmethod::print_inlining_database() {
00888   print_inlining_database_on(std);
00889 }
00890 
00891 
00892 void nmethod::print_inlining_database_on(outputStream* st) {
00893   // WARNING: this method is for debugging only -- it's not used to actually file out the DB
00894   ResourceMark rm;
00895   RScope* root = RNonDummyScope::constructRScopes(this, false);
00896   GrowableArray<PcDesc*>* uncommon = uncommonBranchList();
00897   root->print_inlining_database_on(st, uncommon);
00898 }
00899 
00900 
00901 static int compare_pcDescs(PcDesc** a, PcDesc** b) {
00902   // to sort by ascending scope and ascending bci
00903   int diff = (*a)->scope - (*b)->scope;
00904   return diff ? diff : (*a)->byteCode - (*b)->byteCode;
00905 }
00906 
00907 
00908 GrowableArray<PcDesc*>* nmethod::uncommonBranchList() {
00909   // return a list of *all* uncommon branches (taken or not) of nm, sorted by scope and bci
00910   // (for inlining DB)
00911   GrowableArray<PcDesc*>* uncommon = new GrowableArray<PcDesc*>(20);
00912   relocIterator iter(this);
00913   while (iter.next()) {
00914     if (iter.type() == relocInfo::uncommon_type) {
00915       uncommon->append(containingPcDesc((char*)iter.word_addr()));
00916     }
00917   }
00918 
00919   uncommon->sort(&compare_pcDescs);
00920   return uncommon;
00921 }
00922 
00923 
00924 inline void nmethod::decay_invocation_count(double decay_factor) {
00925   double new_count = (double) invocation_count() / decay_factor;
00926   set_invocation_count((int) new_count);
00927 }
00928 
00929 
00930 // Perform a sweeper task
00931 void nmethod::sweeper_step(double decay_factor) {
00932   // Ignore zombies
00933   if (isZombie()) return;
00934   decay_invocation_count(decay_factor);
00935   _uncommon_trap_counter = int(_uncommon_trap_counter / decay_factor);
00936   cleanup_inline_caches();
00937   incrementAge();
00938 }
00939 
00940 
00941 bool nmethod::isYoung() { 
00942   if (!UseNMethodAging) return false;
00943   if (!flags.isYoung) return false; 
00944   // flags.isYoung == 1, but maybe it has become old in the meantime
00945   if (age() >= NMethodAgeLimit ||
00946       invocation_count() >= InvocationCounterLimit) {
00947     makeOld();
00948   }
00949   return flags.isYoung;
00950 }
00951 
00952 
00953 void nmethod_init() {
00954   // make sure you didn't forget to adjust the filler fields
00955   assert(sizeof(nmFlags) <= 4, "nmFlags occupies more than a word");
00956 }
00957 
00958   nmethod* nmethod_from_insts(char* insts) {    // for efficiency
00959     nmethod* nm = (nmethod*) insts - 1;
00960     return findNMethod(nm);
00961   }
00962 
00963 
00964 # endif

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