compiledPIC.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.37 $ */
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/_compiledPIC.cpp.incl"
00029 
00030 
00031 // A PIC implements a Polymorphic Inline Cache for compiled code.
00032 // The layout comes in 3 variants: a) PICs that contain only m methodOop
00033 // entries, b) PICs that contain both, n nmethod and m methodOop entries
00034 // and c) MICs (Megamorphic Inline Caches) which keep only the selector
00035 // so lookup is fast.The 3 formats can be distinguished by looking at
00036 // the first instruction.
00037 //
00038 // Layout a)            (methodOop entries only)
00039 //
00040 //  0                   : call PIC stub routine
00041 //  5                   : m methodOop entries a 8 bytes each
00042 //  5 + m*8             : <end of PIC>
00043 //
00044 // i.th methodOop entry (0 <= i < m; m > 0)
00045 //
00046 //  5 + i*8             : klass(i)
00047 //  9 + i*8             : methodOop(i)
00048 //
00049 //
00050 // Layout b)            (nmethod & methodOop entries)
00051 //
00052 //  0                   : test al, Mem_Tag
00053 //  2                   : jz smi_nmethod/jz methodOop call stub/jz cache_miss
00054 //  8                   : mov edx, [eax.klass] (always here to simplify iteration, even if n = 0)
00055 // 11                   : n nmethod entries a 12 bytes each
00056 // 11 + n*12            : call PIC stub routine (m > 0)/jmp cache_miss (m = 0)
00057 // 16 + n*12            : m methodOop entries a 8 bytes each
00058 // 16 + n*12 + m*8      : <end of PIC>
00059 //
00060 // i.th nmethod entry (0 <= i < n; n >= 0):
00061 //
00062 // 11 + i*12            : cmp edx, klass(i)
00063 // 11 + i*12 + 6        : je nmethod(i)
00064 //
00065 // i.th methodOop (0 <= i < m; m >= 0):
00066 //
00067 // 16 + n*12 + i*8      : klass
00068 // 16 + n*12 + i*8 + 4  : methodOop
00069 //
00070 //
00071 // Layout c)            (megamorphic inline cache, selector only)
00072 //
00073 //  0                   : call MIC stub routine
00074 //  5                   : selector
00075 //  9                   : <end of MIC>
00076 //
00077 // The PIC stub routine interprets the remaining entries of the PIC; there
00078 // are different stub routines for different m (starting point for interpretation
00079 // is the return address). Entries for smis are treated especially in the sense
00080 // that an initial check for them is always there.
00081 //
00082 // NB: The reason for interpreting the interpreter entries is space, a smallest
00083 // native code implementation for these cases requires 18 bytes per entry (cmp,
00084 // je and load of methodOop). Furthermore, in each case it would be necessary
00085 // to call a stub routine to setup an interpreter frame anyway.
00086 //
00087 // The MIC stub routine interprets the one entry in the MIC. In case of a miss,
00088 // no new PIC/MIC is generated but the current entries are updated. The reason
00089 // for having a specialized PIC allocated in the MIC case is only so the selector
00090 // can be stored. It is used for fast lookup (usually the selector is recomputed
00091 // via debug-info from the corresponding interpreted method).
00092 
00093 
00094 // Opcodes for code pattern generation/parsing
00095 static const char   test_opcode = '\xa8';
00096 static const char   call_opcode = '\xe8';
00097 static const char   jmp_opcode  = '\xe9';
00098 static const uint16 jz_opcode   = 0x840f;
00099 static const uint16 mov_opcode  = 0x508b;
00100 static const uint16 cmp_opcode  = 0xfa81;       static const int cmp_opcode_size = sizeof(uint16);
00101 
00102 
00103 // Helper routines for code pattern generation/parsing
00104 static inline void  put_byte(char*& p, u_char b){ *p++ = b; }
00105 static inline void  put_shrt(char*& p, uint16 s){ *(uint16*)p = s; p += sizeof(uint16); }
00106 static inline void  put_word(char*& p, int w)   { *(int*)p = w; p += sizeof(int); }
00107 static inline void  put_disp(char*& p, char* d) { put_word(p, (int)(d - p - sizeof(int))); }
00108 
00109 static inline int   get_shrt(char* p)           { return *(uint16*)p; }
00110 static inline char* get_disp(char* p)           { return *(int*)p + p + sizeof(int); }
00111 
00112 
00113 // Structure for storing the entries of a PIC
00114 class PIC_contents {
00115  public:
00116   // smi case
00117   char*         smi_nmethod;
00118   methodOop     smi_methodOop;
00119 
00120   // nmethod entries
00121   klassOop      nmethod_klasses[PIC::max_nof_entries];
00122   char*         nmethods[PIC::max_nof_entries];
00123   int n;        // nmethods index
00124 
00125   // methodOop entries
00126   klassOop      methodOop_klasses[PIC::max_nof_entries];
00127   methodOop     methodOops[PIC::max_nof_entries];
00128   int m;        // methodOops index
00129 
00130   void append_nmethod_entry(klassOop klass, char* entry);
00131   void append_method(klassOop klass, methodOop method);
00132 
00133   int number_of_compiled_targets() const        { return (smi_nmethod   ? 1 : 0) + n; }
00134   int number_of_interpreted_targets() const     { return (smi_methodOop ? 1 : 0) + m; }
00135   int number_of_targets() const                 { return number_of_compiled_targets() + number_of_interpreted_targets(); }
00136 
00137   bool has_smi_case() const                     { return (smi_methodOop != NULL) || (smi_nmethod != NULL); }
00138   bool has_nmethods() const                     { return (n > 0) || (smi_nmethod != NULL); }
00139 
00140 
00141   int code_size() const {
00142     int methodOop_size = number_of_interpreted_targets() * PIC::PIC_methodOop_entry_size;
00143     if (has_nmethods()) {
00144       return PIC::PIC_methodOop_entry_offset + n * PIC::PIC_nmethod_entry_size + methodOop_size;
00145     } else {
00146       return PIC::PIC_methodOop_only_offset + methodOop_size;
00147     }
00148   }
00149 
00150 
00151   PIC_contents() {
00152     smi_nmethod   = NULL;
00153     smi_methodOop = NULL;
00154     n = 0;
00155     m = 0;
00156   }
00157 };
00158 
00159 
00160 void PIC_contents::append_nmethod_entry(klassOop klass, char* entry) {
00161   // add new entry
00162   if (klass == smiKlassObj) {
00163     assert(!has_smi_case(), "cannot overwrite smi case");
00164     smi_nmethod = entry;
00165   } else {
00166     nmethod_klasses[n] = klass;
00167     nmethods[n] = entry;
00168     n++;
00169   }
00170 }
00171 
00172 
00173 void PIC_contents::append_method(klassOop klass, methodOop method) {
00174   // add new entry
00175   assert(method->is_method(), "must be methodOop");
00176   if (klass == smiKlassObj) {
00177     assert(!has_smi_case(), "cannot overwrite smi case");
00178     smi_methodOop = method;
00179   } else {
00180     methodOop_klasses[m] = klass;
00181     methodOops[m] = method;
00182     m++;
00183   }
00184 }
00185 
00186 
00187 // Implementation of PIC_Iterators
00188 
00189 PIC_Iterator::PIC_Iterator(PIC* pic) {
00190   _pic   = pic;
00191   _pos   = pic->entry();
00192   // determine initial state
00193   if (pic->is_megamorphic()) {
00194     // MIC -> do not use cached information
00195     assert(get_disp(_pos + 1) == StubRoutines::megamorphic_ic_entry(), "MIC stub expected");
00196     _state = at_the_end;
00197   } else if (*_pos == call_opcode) {
00198     // PIC without nmethods
00199     _state = at_methodOop;
00200     _methodOop_counter = PIC::nof_entries(get_disp(_pos + 1));
00201     _pos += PIC::PIC_methodOop_only_offset;
00202   } else {
00203     // nmethods -> handle smis first
00204     char* dest = get_disp(_pos + PIC::PIC_smi_nmethod_offset);
00205     if (dest == CompiledIC::normalLookupRoutine() || _pic->contains(dest)) {
00206       // no smis or smi case is treated in methodOop section
00207       _state = at_nmethod;
00208       _pos += PIC::PIC_nmethod_entry_offset;
00209     } else {
00210       // smi entry is treated here
00211       _state = at_smi_nmethod;
00212     }
00213   }
00214 }
00215 
00216 
00217 void PIC_Iterator::computeNextState() {
00218   if (get_shrt(_pos) == cmp_opcode) {
00219      // same state
00220   } else if (*_pos == call_opcode) {
00221      _state = at_methodOop;
00222      _methodOop_counter = PIC::nof_entries(get_disp(_pos + 1));
00223      _pos += PIC::PIC_methodOop_entry_offset - PIC::PIC_nmethod_entry_offset;
00224   } else {
00225     assert(*_pos == jmp_opcode, "jump to lookup routine expected");
00226     _state = at_the_end;
00227   }
00228 }
00229 
00230 
00231 void PIC_Iterator::advance() {
00232   switch (_state) {
00233     case at_smi_nmethod:
00234       assert(_pos == _pic->entry(), "must be at beginning");
00235       _pos += PIC::PIC_nmethod_entry_offset;
00236       _state = at_nmethod;
00237       computeNextState();
00238       break;
00239     case at_nmethod:
00240       _pos += PIC::PIC_nmethod_entry_size;
00241       computeNextState();
00242       break;
00243     case at_methodOop:
00244       if (--_methodOop_counter > 0) {
00245         _pos += PIC::PIC_methodOop_entry_size;
00246       } else {
00247         _state = at_the_end;
00248       }
00249       break;
00250     case at_the_end:
00251       ShouldNotCallThis();
00252     default:
00253       ShouldNotReachHere();
00254   }
00255 }
00256 
00257 
00258 klassOop* PIC_Iterator::klass_addr() const {
00259   int offs;
00260   switch (state()) {
00261     case at_smi_nmethod: ShouldNotCallThis();                   // no klass stored -> no klass address available
00262     case at_nmethod    : offs = PIC::PIC_nmethod_klass_offset;  break;
00263     case at_methodOop  : offs = PIC::PIC_methodOop_klass_offset;break;
00264     case at_the_end    : ShouldNotCallThis();                   // no klass stored -> no klass address available
00265     default            : ShouldNotReachHere();
00266   }
00267   return (klassOop*)(_pos + offs);
00268 }
00269 
00270 
00271 int* PIC_Iterator::nmethod_disp_addr() const {
00272   int offs;
00273   switch (state()) {
00274     case at_smi_nmethod: offs = PIC::PIC_smi_nmethod_offset;    break;
00275     case at_nmethod    : offs = PIC::PIC_nmethod_offset;        break;
00276     case at_methodOop  : ShouldNotCallThis();                   // no nmethod stored -> no nmethod address available
00277     case at_the_end    : ShouldNotCallThis();                   // no nmethod stored -> no nmethod address available
00278     default            : ShouldNotReachHere();
00279   }
00280   return (int*)(_pos + offs);
00281 }
00282 
00283 
00284 methodOop* PIC_Iterator::methodOop_addr() const {
00285   int offs;
00286   switch (state()) {
00287     case at_smi_nmethod: ShouldNotCallThis();                   // no methodOop stored -> no methodOop address available
00288     case at_nmethod    : ShouldNotCallThis();                   // no methodOop stored -> no methodOop address available
00289     case at_methodOop  : offs = PIC::PIC_methodOop_offset;      break;
00290     case at_the_end    : ShouldNotCallThis();
00291     default            : ShouldNotReachHere();
00292   }
00293   return (methodOop*)(_pos + offs);
00294 }
00295 
00296 
00297 void PIC_Iterator::print() {
00298   lprintf("a PIC_Iterator\n");
00299 }
00300 
00301 
00302 // Implementation of PICs
00303 
00304 bool PIC::in_heap(char* addr) {
00305   return Universe::code->picHeap->contains(addr);
00306 }
00307 
00308 
00309 PIC* PIC::find(char* addr) {
00310   if (Universe::code->picHeap->contains(addr)) {
00311     PIC* result = (PIC*)Universe::code->picHeap->findStartOfBlock(addr);
00312     return result;
00313   }
00314   return NULL;
00315 }
00316 
00317 
00318 // Accessing PIC entries
00319 klassOop PIC_Iterator::get_klass() const { 
00320   return state() == at_smi_nmethod ? smiKlassObj : *klass_addr(); 
00321 }
00322 
00323 
00324 char* PIC_Iterator::get_call_addr() const { 
00325   int* a = nmethod_disp_addr(); 
00326   return (char*)a + sizeof(int) + *a; 
00327 }
00328 
00329 
00330 bool PIC_Iterator::is_compiled() const {
00331   switch (state()) {
00332     case at_smi_nmethod: return true;
00333     case at_nmethod    : return true;
00334     case at_methodOop  : return false;
00335     case at_the_end    : ShouldNotCallThis();
00336     default            : ShouldNotReachHere();
00337   }
00338   return false;
00339 }
00340 
00341 
00342 bool PIC_Iterator::is_interpreted() const { 
00343   return !is_compiled();
00344 }
00345 
00346 
00347 nmethod* PIC_Iterator::compiled_method() const { 
00348   if (!is_compiled()) return NULL;  
00349   return findNMethod(get_call_addr() - sizeof(nmethod)); 
00350 }
00351 
00352 
00353 methodOop PIC_Iterator::interpreted_method() const { 
00354   if (is_interpreted()) {
00355     return *methodOop_addr(); 
00356   } else {
00357     return compiled_method()->method();
00358   }
00359 }
00360 
00361 
00362 // Modifying PIC entries
00363 void PIC_Iterator::set_klass(klassOop klass) { 
00364   assert(state() != at_smi_nmethod, "cannot be set"); 
00365   *klass_addr() = klass; 
00366 }
00367 
00368 
00369 void PIC_Iterator::set_nmethod(nmethod* nm) { 
00370   assert(get_klass() == nm->key.klass(), "mismatched receiver klass");
00371   int* a = nmethod_disp_addr(); 
00372   *a = nm->verifiedEntryPoint() - (char*)a - sizeof(int); 
00373 }
00374 
00375 
00376 void PIC_Iterator::set_methodOop(methodOop method) { 
00377   *methodOop_addr() = method; 
00378 }
00379 
00380 
00381 symbolOop* PIC::MIC_selector_address() const {
00382   assert(is_megamorphic(), "not a MIC");
00383   return (symbolOop*)(entry() + MIC_selector_offset);
00384 }
00385 
00386 
00387 PIC* PIC::replace(nmethod* nm) {
00388   // nothing to do in megamorphic case
00389   if (is_megamorphic()) return this;
00390 
00391   LOG_EVENT3("compiled PIC at 0x%x: new nmethod 0x%x for klass 0x%x replaces old entry", this, nm, nm->key.klass());
00392 
00393   { // do the replace without creating a new PIC if possible
00394     PIC_Iterator it(this);
00395     while (it.get_klass() != nm->key.klass()) it.advance();
00396     assert(!it.at_end(), "unexpected end during replace");
00397     if (it.is_compiled()) {
00398       it.set_nmethod(nm);
00399       return this;
00400     }
00401   }
00402    
00403   { // Create a new PIC 
00404     PIC_contents contents;
00405     PIC_Iterator it(this);
00406     while (!it.at_end()) {
00407       klassOop receiver_klass = it.get_klass();
00408       if (receiver_klass == nm->key.klass()) {
00409         contents.append_nmethod_entry(nm->key.klass(), nm->verifiedEntryPoint());
00410       } else {
00411         if (it.is_interpreted()) {
00412           contents.append_method(it.get_klass(), it.interpreted_method());
00413         } else {
00414           contents.append_nmethod_entry(it.get_klass(), it.get_call_addr());
00415         }
00416       }
00417       it.advance();
00418     }
00419     int allocated_code_size = contents.code_size();
00420     return new (allocated_code_size) PIC(_ic, &contents, allocated_code_size);
00421   }
00422 }
00423 
00424 
00425 PIC* PIC::cleanup(nmethod** nm) {
00426   // nothing to do in megamorphic case
00427   if (is_megamorphic()) return this;
00428 
00429   bool pic_layout_has_changed = false;
00430 
00431   // Iterate over the PIC and
00432   //  - patch the PIC if possible
00433   //  - check if the layout has changed
00434   //  - collect the PIC information.
00435 
00436   PIC_contents contents;
00437   PIC_Iterator it(this);
00438   while (!it.at_end()) {
00439     klassOop receiver_klass = it.get_klass();
00440     if (it.is_interpreted()) {
00441       // Interpreted methodOop
00442       if(compiled_ic()->isSuperSend()) {
00443         contents.append_method(it.get_klass(), it.interpreted_method());
00444       } else {
00445         LookupKey key(it.get_klass(), it.interpreted_method()->selector());
00446         LookupResult result = lookupCache::lookup(&key);
00447         if (result.matches(it.interpreted_method())) {
00448           contents.append_method(it.get_klass(), it.interpreted_method());
00449         } else {
00450           if (result.is_method()) {
00451             contents.append_method(it.get_klass(), result.method());
00452             it.set_methodOop(result.method());
00453           } else if (result.is_entry()) {
00454             contents.append_nmethod_entry(it.get_klass(), result.get_nmethod()->verifiedEntryPoint());
00455             pic_layout_has_changed = true;
00456           } else {
00457             pic_layout_has_changed = true;
00458           }
00459         }
00460       }
00461     } else {
00462       // Compiled nmethod
00463       nmethod* nm = it.compiled_method();
00464       LookupResult result = lookupCache::lookup(&nm->key);
00465       if (result.matches(nm)) {
00466         contents.append_nmethod_entry(it.get_klass(), it.get_call_addr());
00467       } else {
00468         if (result.is_method()) {
00469           contents.append_method(it.get_klass(), result.method());
00470           pic_layout_has_changed = true;
00471         } else if (result.is_entry()) {
00472           contents.append_nmethod_entry(it.get_klass(), result.get_nmethod()->verifiedEntryPoint());
00473           it.set_nmethod(result.get_nmethod());
00474         } else {
00475           pic_layout_has_changed = true;
00476         }
00477       }
00478     }
00479     it.advance();
00480   }
00481 
00482   *nm = NULL;
00483   if (pic_layout_has_changed) {
00484     
00485     if (contents.number_of_targets() == 0) {
00486       // no targets left
00487       return NULL;
00488     }
00489 
00490     if (contents.number_of_targets() == 1 && contents.has_nmethods()) {
00491       // 1 nmethod target
00492       *nm = findNMethod(contents.has_smi_case() ? contents.smi_nmethod : contents.nmethods[0]);
00493       assert(*nm, "nmethod must be present");
00494       return NULL;
00495     }
00496 
00497     int allocated_code_size = contents.code_size();
00498     return new (allocated_code_size) PIC(_ic, &contents, allocated_code_size);
00499   }
00500 
00501   // The layout has not changed so return the patched self
00502   return this;
00503 }
00504 
00505 
00506 int PIC::nof_entries(char* pic_stub) {
00507   int i = 1;
00508   while (true) {
00509     if (pic_stub == StubRoutines::PIC_stub_entry(i)) return i;
00510     i++;
00511   }
00512   ShouldNotReachHere();
00513   return 0;
00514 }
00515 
00516 
00517 int PIC::code_for_methodOops_only(char* entry, PIC_contents* c) {
00518   char* p = entry;
00519   put_byte(p, call_opcode);
00520   if (c->smi_methodOop == NULL) {
00521     // no smi methodOop
00522     put_disp(p, StubRoutines::PIC_stub_entry(c->m));
00523     assert(entry + PIC_methodOop_only_offset == p, "constant inconsistent");
00524   } else {
00525     // handle smi methodOop first
00526     put_disp(p, StubRoutines::PIC_stub_entry(1 + c->m));
00527     put_word(p, int(smiKlassObj));
00528     put_word(p, int(c->smi_methodOop));
00529     assert(entry + PIC_methodOop_only_offset + PIC_methodOop_entry_size == p, "constant value inconsistent with code pattern");
00530   }
00531   char* p1 = p;
00532   for (int i = 0; i < c->m; i++) {
00533     assert(c->methodOop_klasses[i] != smiKlassObj, "should not be smiKlassObj");
00534     put_word(p, int(c->methodOop_klasses[i]));
00535     put_word(p, int(c->methodOops[i]));
00536   }
00537   assert(p1 + c->m * PIC_methodOop_entry_size == p, "constant value inconsistent with code pattern");
00538   return p - entry;
00539 }
00540 
00541 
00542 int PIC::code_for_polymorphic_case(char* entry, PIC_contents* c) {
00543   if (c->has_nmethods()) {
00544     // nmethods & methodOops
00545     // test al, Mem_Tag
00546     char* p     = entry;
00547     char* fixup = NULL;
00548     put_byte(p, test_opcode);
00549     put_byte(p, Mem_Tag);
00550     // jz ...
00551     put_shrt(p, jz_opcode);
00552     if (c->smi_nmethod != NULL) {
00553       assert(c->smi_methodOop == NULL, "can only have one method for smis");
00554       put_disp(p, c->smi_nmethod);
00555     } else if (c->smi_methodOop != NULL) {
00556       // smi method is methodOop -> handle it in methodOop section
00557       fixup = p;
00558       put_disp(p, 0);
00559     } else {
00560       // no smi entries
00561       put_disp(p, CompiledIC::normalLookupRoutine()); // Fix this for super sends!
00562     }
00563     // always load klass to simplify decoding/iteration of PIC
00564     // mov edx, [eax.klass]
00565     put_shrt(p, mov_opcode);
00566     put_byte(p, memOopDesc::klass_byte_offset());
00567     assert(entry + PIC_nmethod_entry_offset == p, "constant value inconsistent with code pattern");
00568     // handle nmethods
00569     for (int i = 0; i < c->n; i++) {
00570       // cmp edx, klass(i)
00571       assert(c->nmethod_klasses[i] != smiKlassObj, "should not be smiKlassObj");
00572       put_shrt(p, cmp_opcode);
00573       assert(entry + PIC_nmethod_entry_offset + i*PIC_nmethod_entry_size + PIC_nmethod_klass_offset == p, "constant value inconsistent with code pattern");
00574       put_word(p, int(c->nmethod_klasses[i]));
00575       // je nmethod(j)
00576       put_shrt(p, jz_opcode);
00577       assert(entry + PIC_nmethod_entry_offset + i*PIC_nmethod_entry_size + PIC_nmethod_offset == p, "constant value inconsistent with code pattern");
00578       put_disp(p, c->nmethods[i]);
00579     }
00580     assert(entry + PIC_nmethod_entry_offset + c->n*PIC_nmethod_entry_size == p, "constant value inconsistent with code pattern");
00581     if (c->smi_methodOop != NULL || c->m > 0) {
00582       // handle methodOops
00583       if (fixup != NULL) put_disp(fixup, p);
00584       p += code_for_methodOops_only(p, c);
00585     } else {
00586       // jmp cache_miss
00587       put_byte(p, jmp_opcode);
00588       put_disp(p, CompiledIC::normalLookupRoutine());
00589     }
00590     return p - entry;
00591   } else {
00592     // no nmethods -> call PIC stub routine directly
00593     return code_for_methodOops_only(entry, c);
00594   }
00595 }
00596 
00597 
00598 int PIC::code_for_megamorphic_case(char* entry) {
00599   char* p = entry;
00600   put_byte(p, call_opcode);
00601   put_disp(p, StubRoutines::megamorphic_ic_entry());
00602   assert(entry + MIC_selector_offset == p, "layout constant inconsistent with code pattern");
00603   put_word(p, int(selector())); // used for fast lookup
00604   assert(entry + MIC_code_size == p, "layout constant inconsistent with code pattern");
00605   return p - entry;
00606 }
00607 
00608 
00609 void PIC::shrink_and_generate(PIC* pic, klassOop klass, void* method) {
00610   Unimplemented();
00611 }
00612 
00613 
00614 void* PIC::operator new(size_t size, int code_size){
00615   return Universe::code->picHeap->allocate(size + code_size);
00616 }
00617 
00618 
00619 void PIC::operator delete(void* p) {
00620   Universe::code->picHeap->deallocate(p, 0);
00621 }
00622 
00623 
00624 PIC* PIC::allocate(CompiledIC* ic, klassOop klass, LookupResult result) {
00625   assert(!result.is_empty(), "lookup result cannot be empty");
00626 
00627   PIC_contents contents;
00628 
00629   // Always add the new entry first
00630   if (result.is_entry()) {
00631     contents.append_nmethod_entry(klass, result.get_nmethod()->verifiedEntryPoint());
00632   } else {
00633     contents.append_method(klass, result.method());
00634   }
00635 
00636   PIC*     old_pic       = ic->pic();
00637   nmethod* old_nmethod   = ic->target();
00638   bool     switch_to_MIC = false;
00639   
00640   // 3 possible cases:
00641   //
00642   // 1. IC is empty but lookup result returns methodOop -> needs 1-element PIC to call methodOop
00643   // 2. IC contains 1 nmethod -> generate 2-element PIC
00644   // 3. IC contains pic -> grow PIC or switch to MIC
00645 
00646   if (old_pic != NULL) {
00647     // ic contains pic
00648     assert(old_nmethod == NULL, "just checking");
00649     assert(!old_pic->is_megamorphic(), "MICs should not change anymore");
00650     if (old_pic->number_of_targets() >= max_nof_entries) {
00651       if (UseMICs) {
00652         // switch to MIC, keep only no lookup result
00653         switch_to_MIC = true;
00654       } else {
00655         ic->resetOptimized();   // make sure it doesn't force the creation of nmethods
00656         return NULL;
00657       }
00658     } else {
00659       // append old PIC entries
00660       PIC_Iterator it(old_pic);
00661       while (!it.at_end()) {
00662         if (it.is_interpreted()) {
00663           contents.append_method(it.get_klass(), it.interpreted_method());
00664         } else {
00665           contents.append_nmethod_entry(it.get_klass(), it.get_call_addr());
00666         }
00667         it.advance();
00668       }
00669     }
00670   } else if (old_nmethod != NULL) {
00671     // ic contains 1 nmethod
00672     contents.append_nmethod_entry(ic->get_klass(0), old_nmethod->verifiedEntryPoint());
00673   } else {
00674     // empty ic -> nothing to do
00675     assert(ic->is_empty(), "just checking");
00676   }
00677 
00678   assert(switch_to_MIC ||
00679          contents.number_of_interpreted_targets() > 0 ||
00680          contents.number_of_compiled_targets() > 1,
00681          "no PIC required for only 1 compiled target");
00682 
00683   PIC* new_pic = NULL;
00684   if (switch_to_MIC) {
00685     new_pic = new (MIC_code_size) PIC(ic);
00686   } else {
00687     int allocated_code_size = contents.code_size();
00688     new_pic = new (allocated_code_size) PIC(ic, &contents, allocated_code_size);
00689   }
00690 
00691   #ifdef ASSERT
00692     new_pic->verify();
00693   #endif
00694 
00695   return new_pic;
00696 }
00697 
00698 
00699 
00700 PIC::PIC(CompiledIC* ic, PIC_contents* contents, int allocated_code_size) {
00701   assert(contents->number_of_targets() >= 1, "at least one entry needed for non-megamorphic case");
00702   _ic                   = ic;
00703   _number_of_targets    = contents->number_of_targets();
00704   _code_size            = code_for_polymorphic_case(entry(), contents);
00705   assert(code_size() == allocated_code_size, "Please adjust PIC_contents::code_size()");
00706 }
00707 
00708 
00709 PIC::PIC(CompiledIC* ic) {
00710   _ic                   = ic;
00711   _number_of_targets    = 0; // indicates megamorphic case
00712   _code_size            = code_for_megamorphic_case(entry());
00713   assert(code_size() == MIC_code_size, "Please adjust PIC_contents::code_size()");
00714 }
00715 
00716 
00717 GrowableArray<klassOop>* PIC::klasses() const {
00718   GrowableArray<klassOop>* k = new GrowableArray<klassOop>(2);
00719   PIC_Iterator it((PIC*)this);
00720   while(!it.at_end()) {
00721     k->append(it.get_klass());
00722     it.advance();
00723   }
00724   return k;
00725 }
00726 
00727 
00728 void PIC::oops_do(void f(oop*)) {
00729   if (is_megamorphic()) {
00730     // cannot use PIC_Iterator (0 entries) -> deal with MIC directly
00731     f((oop*)MIC_selector_address());
00732   } else {
00733     PIC_Iterator it(this);
00734     while(!it.at_end()) {
00735       switch(it.state()) {
00736         case PIC_Iterator::at_methodOop: f((oop*) it.methodOop_addr());  // fall through
00737         case PIC_Iterator::at_nmethod  : f((oop*) it.klass_addr());
00738       }
00739       it.advance();
00740     }
00741   }
00742 }
00743 
00744 
00745 void PIC::print() {
00746   lprintf("\tPIC with %d entr%s\n", number_of_targets(), number_of_targets() == 1 ? "y" : "ies");
00747   lprintf("\t- selector    : ");
00748   selector()->print_symbol_on();
00749   lprintf("\n");
00750 
00751   // Disassembler::decode(entry(), entry() + code_size());
00752 
00753   int i = 1;
00754   PIC_Iterator it(this);
00755   while (!it.at_end()) {
00756     lprintf("\t- %d. klass    : ", i);
00757     it.get_klass()->print_value();
00758     lprintf("\n");
00759     switch (it.state()) {
00760       case PIC_Iterator::at_smi_nmethod: // fall through
00761       case PIC_Iterator::at_nmethod    : printf("\t-    nmethod  : %#x (entry %#x)\n", 
00762                                                     (int)it.compiled_method(), (int)it.get_call_addr()); break;
00763       case PIC_Iterator::at_methodOop  : printf("\t-    methodOop: %s\n", it.interpreted_method()->print_value_string()); break;
00764       default: ShouldNotReachHere();
00765     }
00766     i++;
00767     it.advance();
00768   }
00769 }
00770 
00771 
00772 void PIC::verify() {
00773   // check for multiple entries for same class
00774   ResourceMark rm;
00775   GrowableArray<klassOop>* k = klasses();
00776   for (int i = 0; i < k->length() - 1; i++) {
00777     for (int j = i + 1; j < k->length(); j++) {
00778       if (k->at(i) == k->at(j)) {
00779         std->print("The class ");
00780         k->at(i)->klass_part()->print_name_on(std);
00781         std->print_cr("is twice in PIC 0x%lx", this);
00782         warning("PIC verify error");
00783       }
00784     }
00785   }
00786 }
00787 
00788 
00789 // Implementation of CompiledIC_Iterator
00790 
00791 CompiledIC_Iterator::CompiledIC_Iterator(CompiledIC* ic) {
00792   _ic = ic;
00793   init_iteration();
00794 }
00795 
00796 
00797 void CompiledIC_Iterator::init_iteration() {
00798   _picit = NULL;
00799   _index = 0;
00800   if (_ic->is_empty()) {
00801     _number_of_targets = 0;
00802     _shape = anamorphic;
00803   } else if (_ic->is_monomorphic()) {
00804     _number_of_targets = 1;
00805     _shape = monomorphic;
00806     PIC* pic = _ic->pic();
00807     if (pic) _picit = new PIC_Iterator(pic);  // calls an interpreted method
00808   } else if (_ic->is_polymorphic()) {
00809     PIC* pic = _ic->pic();
00810     _number_of_targets = pic->number_of_targets();
00811     _shape = polymorphic;
00812     _picit = new PIC_Iterator(pic);
00813   } else if (_ic->is_megamorphic()) {
00814     _number_of_targets = 0;
00815     _shape = megamorphic;
00816   } else {
00817     ShouldNotReachHere();
00818   }
00819 }
00820 
00821 
00822 void CompiledIC_Iterator::advance() {
00823   assert(!at_end(), "iterated over the end");
00824   if (_picit != NULL) {
00825     _picit->advance();
00826   }
00827   _index++;
00828 }
00829 
00830 
00831 klassOop CompiledIC_Iterator::klass() const {
00832   assert(!at_end(), "iterated over the end");
00833   if (_picit != NULL) {
00834     return _picit->get_klass();
00835   } else {
00836     return _ic->get_klass(0);
00837   }
00838 }
00839 
00840 
00841 bool CompiledIC_Iterator::is_interpreted() const {
00842   assert(!at_end(), "iterated over the end");
00843   if (_picit != NULL) {
00844     return _picit->is_interpreted();
00845   } else {
00846     return false;
00847   }
00848 }
00849 
00850 
00851 bool CompiledIC_Iterator::is_compiled() const {
00852   assert(!at_end(), "iterated over the end");
00853   if (_picit != NULL) {
00854     return _picit->is_compiled();
00855   } else {
00856     return true;
00857   }
00858 }
00859 
00860 
00861 bool CompiledIC_Iterator::is_super_send() const {
00862   extern bool SuperSendsAreAlwaysInlined;
00863   assert(SuperSendsAreAlwaysInlined, "fix this");
00864   return false;         // for now, super sends are always inlined
00865 }
00866 
00867 
00868 methodOop CompiledIC_Iterator::interpreted_method() const {
00869   assert(!at_end(), "iterated over the end");
00870   if (_picit != NULL) {
00871     return _picit->interpreted_method();
00872   } else {
00873     return compiled_method()->method();
00874   }
00875 }
00876 
00877 
00878 nmethod* CompiledIC_Iterator::compiled_method() const {
00879   assert(!at_end(), "iterated over the end");
00880   if (_picit != NULL) {
00881     return _picit->compiled_method();
00882   } else {
00883     assert(number_of_targets() == 1, "must be monomorphic");
00884     return _ic->target();
00885   }
00886 }
00887 
00888 
00889 void CompiledIC_Iterator::print() {
00890   lprintf("CompiledIC_Iterator for ((CompiledIC*)%#x) (%s)\n", _ic, selector()->as_string());
00891 }
00892 
00893 #endif

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