stubRoutines.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.44 $ */
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 
00025 # include "incls/_precompiled.incl"
00026 # include "incls/_stubRoutines.cpp.incl"
00027 
00028 const int max_fast_allocate_size = 9;
00029 
00030 // entry points
00031 char* StubRoutines::_ic_normal_lookup_entry     = NULL;
00032 char* StubRoutines::_ic_super_lookup_entry      = NULL;
00033 char* StubRoutines::_zombie_nmethod_entry       = NULL;
00034 char* StubRoutines::_zombie_block_nmethod_entry = NULL;
00035 char* StubRoutines::_megamorphic_ic_entry       = NULL;
00036 char* StubRoutines::_compile_block_entry        = NULL;
00037 char* StubRoutines::_continue_NLR_entry         = NULL;
00038 char* StubRoutines::_call_sync_DLL_entry        = NULL;
00039 char* StubRoutines::_call_async_DLL_entry       = NULL;
00040 char* StubRoutines::_lookup_sync_DLL_entry      = NULL;
00041 char* StubRoutines::_lookup_async_DLL_entry     = NULL;
00042 char* StubRoutines::_recompile_stub_entry       = NULL;
00043 char* StubRoutines::_used_uncommon_trap_entry   = NULL;
00044 char* StubRoutines::_unused_uncommon_trap_entry = NULL;
00045 char* StubRoutines::_verify_context_chain_entry = NULL;
00046 char* StubRoutines::_deoptimize_block_entry     = NULL;
00047 char* StubRoutines::_call_inspector_entry       = NULL;
00048 
00049 char* StubRoutines::_PIC_stub_entries[PIC::max_nof_entries + 1];        // entry 0 ignored
00050 char* StubRoutines::_allocate_entries[max_fast_allocate_size + 1];
00051 
00052 
00053 // tracing
00054 
00055 void StubRoutines::trace_DLL_call_1(dll_func function, oop* last_argument, int nof_arguments) {
00056   if (!TraceDLLCalls) return; // in case it has been turned off during run-time
00057   frame f = DeltaProcess::active()->last_frame();
00058   if (f.is_interpreted_frame()) {
00059     // called from within interpreter -> InterpretedDLL_Cache available
00060     methodOop m = f.method();
00061     CodeIterator it(m, m->bci_from(f.hp()));
00062     InterpretedDLL_Cache* cache = it.dll_cache();
00063     assert(cache->entry_point() == function, "inconsistency with InterpretedDLL_Cache");
00064     assert(cache->number_of_arguments() == nof_arguments, "inconsistency with InterpretedDLL_Cache");
00065     cache->print();
00066   } else {
00067     // called from within compiled code -> CompiledDLL_Cache available
00068     CompiledDLL_Cache* cache = compiledDLL_Cache_from_return_address(f.pc());
00069     assert(cache->entry_point() == function, "inconsistency with CompiledDLL_Cache");
00070     cache->print();
00071   }
00072   // print arguments
00073   int i = 1;
00074   oop* arg_ptr = last_argument + (nof_arguments - 1);
00075   for (i = 1; i <= nof_arguments; i++, arg_ptr--) {
00076     oop arg = *arg_ptr;
00077     std->print("%6d. ", i);
00078     if (arg->is_smi()) {
00079       std->print("smi   value = %d\n", ((smiOop)arg)->value());
00080     } else {
00081       std->print("proxy value = 0x%08x (proxy = 0x%08x)\n", ((proxyOop)arg)->get_pointer(), arg);
00082     }
00083   }
00084 }
00085 
00086 
00087 void StubRoutines::trace_DLL_call_2(int result) {
00088   if (!TraceDLLCalls) return; // in case it has been turned off during run-time
00089   std->print("    result = 0x%08x\n", result);
00090 }
00091 
00092 
00093 void StubRoutines::wrong_DLL_call() {
00094   { ResourceMark rm;
00095     std->print("DLL call error: number of arguments probably wrong\n");
00096   }
00097   if (DeltaProcess::active()->is_scheduler()) {
00098     DeltaProcess::active()->trace_stack();
00099     fatal("DLL error in scheduler");
00100   } else {
00101     DeltaProcess::active()->suspend(::DLL_lookup_error);
00102   }
00103   ShouldNotReachHere();
00104 }
00105 
00106 
00107 // generators
00108 
00109 char* StubRoutines::generate_ic_lookup(MacroAssembler* masm, char* lookup_routine_entry) {
00110 // Stub routine that calls icLookup which patches the icache.
00111 // After returning from icLookup the send is continued. The
00112 // icLookupStub is called from empty iCaches within compiled
00113 // code.
00114 //
00115 // Note that so far, the lookup routine doesn't do allocation,
00116 // therefore the receiver can be saved/restored on the C stack.
00117 // (This has to be fixed as soon as 'message not understood' is
00118 // handled correctly from within compiled code.
00119   
00120   // eax: receiver
00121   // tos: return address
00122   char* entry_point = masm->pc();
00123   masm->set_last_Delta_frame_after_call();
00124   masm->movl(ebx, Address(esp));                // get return address (= ic address)
00125   masm->pushl(eax);                             // save receiver
00126   masm->pushl(ebx);                             // pass ic
00127   masm->pushl(eax);                             // pass receiver
00128   masm->call(lookup_routine_entry, relocInfo::runtime_call_type);       // eax = lookup_routine(receiver, ic)
00129   masm->movl(ebx, eax);                         // ebx = method code
00130   masm->popl(eax);                              // get rid of receiver argument
00131   masm->popl(eax);                              // get rid of ic argument
00132   masm->popl(eax);                              // restore receiver (don't use argument, might be overwritten)
00133   masm->reset_last_Delta_frame();
00134   masm->jmp(ebx);                               // jump to target
00135   return entry_point;
00136 }
00137 
00138 
00139 extern "C" char* icNormalLookup(oop recv, CompiledIC* ic);
00140 extern "C" char* icSuperLookup (oop recv, CompiledIC* ic);
00141 extern "C" char* zombie_nmethod(CompiledIC* ic);
00142 
00143 char* StubRoutines::generate_ic_normal_lookup(MacroAssembler* masm) {
00144   return generate_ic_lookup(masm, (char*)icNormalLookup);
00145 }
00146 
00147 
00148 char* StubRoutines::generate_ic_super_lookup(MacroAssembler* masm) {
00149   return generate_ic_lookup(masm, (char*)icSuperLookup);
00150 }
00151 
00152 
00153 char* StubRoutines::generate_zombie_nmethod(MacroAssembler* masm) {
00154 // Called from zombie nmethods immediately after they are called.
00155 // Does cleanup of interpreted/compiled ic and redoes the send.
00156 //
00157 // Note: zombie_nmethod() doesn't do scavenge (otherwise this code
00158 //       has to change - the receiver cannot be saved on the stack).
00159 
00160   // eax  : receiver
00161   // tos  : return address to zombie nmethod (which called this stub)
00162   // tos-4: return address to caller nmethod (which called the zombie nmethod)
00163   char* entry_point = masm->pc();
00164   masm->popl(ebx);                              // get rid of return address to zombie nmethod
00165   // eax: receiver
00166   // tos: return address to caller nmethod (which called the zombie nmethod)
00167   masm->set_last_Delta_frame_after_call();
00168   masm->movl(ebx, Address(esp));                // get return address (= ic address) - don't pop! (needed for correct Delta frame)
00169   masm->pushl(eax);                             // save receiver
00170   masm->pushl(ebx);                             // pass ic
00171   masm->call((char*)zombie_nmethod, relocInfo::runtime_call_type);      // eax = zombie_nmethod(return_address)
00172   masm->movl(ecx, eax);                         // ecx = entry point to redo send
00173   masm->popl(ebx);                              // get rid of ic argument
00174   masm->popl(eax);                              // restore receiver
00175   masm->popl(ebx);                              // get rid of return address
00176   masm->reset_last_Delta_frame();
00177   masm->jmp(ecx);                               // redo send
00178   return entry_point;
00179 }
00180 
00181 // The code below (validateContextChain(...) and generate_verify_context_chain(...)
00182 // can be removed if it turns out that the new solution (using deoptimize_block()
00183 // and generate_deoptimize_block(...)) is working correctly. See also call site
00184 // (code for PrologueNode). - gri 6/25/96
00185 
00186 static bool validateContextChain(blockClosureOop block) {
00187   assert(block->is_block(), "must be block");
00188   bool is_valid = true;
00189 
00190   { contextOop con = block->lexical_scope();
00191     // verify entire context chain
00192     assert(con->is_context(), "expecting a context");
00193 
00194     while (true) {
00195       if (con->unoptimized_context() != NULL) {
00196         is_valid = false;
00197         break;
00198       }
00199       if (!con->has_outer_context()) break; 
00200       con = con->outer_context();
00201     }
00202   }
00203 
00204   if (is_valid) return true;
00205 
00206   assert(block->isCompiledBlock(), "we should be in a compiled block");
00207 
00208   // Patch the blockClosure
00209   methodOop method = block->method();
00210   nmethod*  nm     = block->jump_table_entry()->block_nmethod();
00211 
00212   LOG_EVENT1("Deoptimized context in blockClosure -> switch to methodOop 0x%lx", nm);
00213   {
00214     block->set_method(method);
00215     contextOop con    = block->lexical_scope();
00216     contextOop un_con = con->unoptimized_context();
00217     if (un_con) {
00218       block->set_lexical_scope(un_con);
00219     } else {
00220       Unimplemented();
00221     }
00222   }
00223   return false;
00224 }
00225 
00226 static void deoptimize_context_and_patch_block(blockClosureOop block) {
00227   assert(block->is_block(), "must be block");
00228   assert(block->isCompiledBlock(), "we should be in a compiled block");
00229 
00230   // Patch the blockClosure
00231   methodOop method = block->method();
00232   nmethod*  nm     = block->jump_table_entry()->block_nmethod();
00233 
00234   LOG_EVENT1("Deoptimized context in blockClosure -> switch to methodOop 0x%lx", nm);
00235 
00236   contextOop con = block->lexical_scope();
00237   block->set_method(method);  
00238   if (method->expectsContext()) {
00239     guarantee(con && con->is_context(), "Optimized context must be present");
00240 
00241     // we have (nm, con) the deoptimize the context
00242     contextOop unoptimized_con = con->unoptimized_context();
00243     guarantee(unoptimized_con && unoptimized_con->is_context(), "Unoptimized context must be present");
00244     block->set_lexical_scope(unoptimized_con);
00245   } else {
00246     guarantee(!con->is_context(), "Cannot be a context");
00247   }
00248 }
00249 
00250 extern "C" void restart_primitiveValue();
00251 
00252 char* StubRoutines::generate_zombie_block_nmethod(MacroAssembler* masm) {
00253 // Called from zombie nmethods immediately after they are called.
00254 // Does cleanup of interpreted/compiled ic and redoes the send.
00255 //
00256 // Note: zombie_nmethod() doesn't do scavenge (otherwise this code
00257 //       has to change - the receiver cannot be saved on the stack).
00258 
00259   // eax  : receiver
00260   // tos  : return address to zombie nmethod (which called this stub)
00261   // tos-4: return address to caller nmethod (which called the zombie nmethod)
00262   char* entry_point = masm->pc();
00263 
00264   masm->set_last_Delta_frame_after_call();
00265   masm->pushl(self_reg); // pass argument (C calling convention)
00266   masm->call((char*)deoptimize_context_and_patch_block, relocInfo::runtime_call_type);
00267   masm->movl(ebx, eax);
00268   masm->popl(self_reg);
00269   masm->reset_last_Delta_frame();
00270   masm->addl(esp, 4);
00271   masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
00272   return entry_point;
00273 }
00274 
00275 extern "C" char* method_entry_point;
00276 
00277 char* StubRoutines::generate_megamorphic_ic(MacroAssembler* masm) {
00278 // Called from within a MIC (megamorphic inline cache), the special
00279 // variant of PICs for compiled code (see compiledPIC.hpp/cpp).
00280 // The MIC layout is as follows:
00281 //
00282 // call <this stub routine>
00283 // selector                     <--- return address (tos)
00284 //
00285 // Note: Don't use this for megamorphic super sends!
00286 
00287   Label is_smi, probe_primary_cache, probe_secondary_cache, call_method, is_methodOop, do_lookup;
00288 
00289   masm->bind(is_smi);                           // smi case (assumed to be infrequent)
00290   masm->movl(ecx, Address((int)&smiKlassObj, relocInfo::external_word_type));
00291   masm->jmp(probe_primary_cache);
00292 
00293   // eax    : receiver
00294   // tos    : return address pointing to selector in MIC
00295   // tos + 4: return address of megamorphic send in compiled code
00296   // tos + 8: last argument/receiver
00297   char* entry_point = masm->pc();
00298   masm->popl(ebx);                              // get return address (MIC cache)
00299   masm->test(eax, Mem_Tag);                     // check if smi
00300   masm->jcc(Assembler::zero, is_smi);           // if so, get smi class directly
00301   masm->movl(ecx, Address(eax, memOopDesc::klass_byte_offset()));       // otherwise, load receiver class
00302 
00303   // probe primary cache
00304   //
00305   // eax: receiver
00306   // ebx: MIC cache pointer
00307   // ecx: receiver klass
00308   // tos: return address of megamorphic send in compiled code (ic)
00309   masm->bind(probe_primary_cache);              // compute hash value
00310   masm->movl(edx, Address(ebx));                // get selector
00311   // compute hash value
00312   masm->movl(edi, ecx);
00313   masm->xorl(edi, edx);
00314   masm->andl(edi, (primary_cache_size - 1) << 4);
00315   // probe cache
00316   masm->cmpl(ecx, Address(edi, lookupCache::primary_cache_address() + 0*oopSize));
00317   masm->jcc(Assembler::notEqual, probe_secondary_cache);
00318   masm->cmpl(edx, Address(edi, lookupCache::primary_cache_address() + 1*oopSize));
00319   masm->jcc(Assembler::notEqual, probe_secondary_cache);
00320   masm->movl(ecx, Address(edi, lookupCache::primary_cache_address() + 2*oopSize));
00321 
00322   // call method
00323   //
00324   // eax: receiver
00325   // ecx: methodOop/nmethod
00326   // tos: return address of megamorphic send in compiled code (ic)
00327   masm->bind(call_method);
00328   masm->test(ecx, Mem_Tag);                     // check if methodOop
00329   masm->jcc(Assembler::notZero, is_methodOop);  // otherwise
00330   masm->jmp(ecx);                               // call nmethod
00331 
00332   // call methodOop - setup registers
00333   masm->bind(is_methodOop);
00334   masm->xorl(ebx, ebx);                         // clear ebx for interpreter
00335   masm->movl(edx, Address(int(&method_entry_point), relocInfo::external_word_type));
00336   // (Note: cannot use value in method_entry_point directly since interpreter is generated afterwards)
00337   //
00338   // eax: receiver
00339   // ebx: 00000000
00340   // ecx: methodOop
00341   // edx: entry point
00342   // tos: return address of megamorphic send in compiled code (ic)
00343   masm->jmp(edx);                               // call method_entry
00344 
00345   // probe secondary cache
00346   //
00347   // eax: receiver
00348   // ebx: MIC cache pointer
00349   // ecx: receiver klass
00350   // edx: selector
00351   // edi: primary cache index
00352   // tos: return address of megamorphic send in compiled code (ic)
00353   masm->bind(probe_secondary_cache);            // compute hash value
00354   masm->andl(edi, (secondary_cache_size - 1) << 4);
00355   // probe cache
00356   masm->cmpl(ecx, Address(edi, lookupCache::secondary_cache_address() + 0*oopSize));
00357   masm->jcc(Assembler::notEqual, do_lookup);
00358   masm->cmpl(edx, Address(edi, lookupCache::secondary_cache_address() + 1*oopSize));
00359   masm->jcc(Assembler::notEqual, do_lookup);
00360   masm->movl(ecx, Address(edi, lookupCache::secondary_cache_address() + 2*oopSize));
00361   masm->jmp(call_method);
00362   
00363   // do lookup
00364   //
00365   // eax: receiver
00366   // ebx: MIC cache pointer
00367   // ecx: receiver klass
00368   // edx: selector
00369   // edi: secondary cache index
00370   // tos: return address of megamorphic send in compiled code (ic)
00371   masm->bind(do_lookup);
00372   masm->set_last_Delta_frame_after_call();
00373   masm->pushl(eax);                             // save receiver
00374   masm->pushl(edx);                             // pass 2nd argument: selector
00375   masm->pushl(ecx);                             // pass 1st argument: receiver klass
00376   masm->call((char*)lookupCache::normal_lookup, relocInfo::runtime_call_type);
00377   masm->movl(ecx, eax);                         // ecx: method
00378   masm->popl(ebx);                              // pop 1st argument
00379   masm->popl(ebx);                              // pop 2nd argument
00380   masm->popl(eax);                              // restore receiver
00381   masm->reset_last_Delta_frame();
00382   masm->testl(ecx, ecx);                        // test if method has been found in lookup cache
00383   masm->jcc(Assembler::notZero, call_method);
00384 
00385   // method not found in the lookup cache - full lookup needed (message not understood may happen)
00386   // eax: receiver
00387   // ebx: points to MIC cache
00388   // tos: return address of megamorphic send in compiled code
00389   //
00390   // Note: This should not happen right now, since normal_lookup always returns a value
00391   //       if the method exists (and 'message not understood' is not yet supported in
00392   //       compiled code). However, this should change at some point, and normal_lookup_cache_probe
00393   //       should be used instead of normal_lookup.
00394   masm->hlt();
00395 
00396   return entry_point;
00397 }
00398 
00399 
00400 char* StubRoutines::generate_compile_block(MacroAssembler* masm) {
00401 // Stub routine that is called from a jumptable entry for a block closure.
00402 // The recipe:
00403 //   - compile the toplevelblock nmethod
00404 //   - patch the jump entry with the entry point of the compiler nmethod
00405 //   - jump to the new nmethod.
00406 //
00407 // Note that compile_new_block doesn't do allocation,
00408 // therefore the receiver can be saved on the C stack.
00409 
00410   // eax: receiver
00411   char* entry_point = masm->pc();
00412   masm->set_last_Delta_frame_after_call();
00413   masm->pushl(eax);                             // save receiver
00414   masm->pushl(eax);                             // pass receiver
00415   masm->call((char*)jumpTable::compile_new_block, relocInfo::runtime_call_type);        // eax = block_closure_compile(receiver)
00416   masm->movl(ebx, eax);                         // ebx = block code
00417   masm->popl(eax);                              // get rid of receiver argument
00418   masm->popl(eax);                              // restore receiver (don't use argument, might be overwritten)
00419   masm->reset_last_Delta_frame();
00420   masm->jmp(ebx);                               // jump to target
00421   return entry_point;
00422 }
00423 
00424 
00425 char* StubRoutines::generate_continue_NLR(MacroAssembler* masm) {
00426 // Entry point jumped to from compiled code. Initiates (or continues an ongoing) NLR.
00427 // Originally this code has been generated in nmethods, using a stub reduces code size.
00428 
00429   Register ret_addr = temp1;
00430   Register offset   = temp2;
00431 
00432   char* entry_point = masm->pc();
00433   masm->leave();                                                // remove stack frame
00434   masm->popl(ret_addr);                                         // get (local) return address
00435   masm->movl(offset, Address(ret_addr, IC_Info::info_offset));  // get ic info
00436   if (IC_Info::number_of_flags > 0) {
00437     masm->sarl(offset, IC_Info::number_of_flags);               // shift ic info flags out
00438   }
00439   masm->addl(ret_addr, offset);                                 // compute non-local return address
00440   masm->jmp(ret_addr);                                          // do NLR
00441   return entry_point;
00442 }
00443 
00444 
00445 char* StubRoutines::generate_call_DLL(MacroAssembler* masm, bool async) {
00446 // The following routine provides the extra frame for DLL calls.
00447 // Note: 1. Its code has to be *outside* the interpreters code! (see also: DLL calls in interpreter)
00448 //       2. This routine is also used by the compiler! Make sure to adjust the parameter
00449 //          passing in the compiler as well (x86_node.cpp, codeGenerator.cpp), when changing this code!
00450 //
00451 // Stack layout immediately after calling the DLL:
00452 // (The DLL state word is used for asynchronous DLL/interrupted DLL calls)
00453 //
00454 //        ...                                   DLL land
00455 // esp->[ return addr   ] ------------------------------------------------------------------------
00456 //      [ unboxed arg 1 ]                       C land
00457 //        ...
00458 //      [ unboxed arg n ]
00459 //      [ ptr to itself ] <---- ptr to itself   to check that the right no. of arguments is used
00460 //      [ DLL state     ]                       used for DLL/interrupted DLL calls
00461 //      [ return addr   ] ------------------------------------------------------------------------
00462 //      [ argument n    ] <---- last_Delta_sp   Delta land
00463 //      [ argument n-1  ]
00464 //        ...
00465 //      [ argument 1    ]
00466 //      [ return proxy  ]
00467 //        ...
00468 // ebp->[ previous ebp  ] <---- last_Delta_fp
00469 //
00470 // The routine expects 3 arguments to be passed in registers as follows:
00471 //
00472 // ebx: number of arguments
00473 // ecx: address of last argument
00474 // edx: DLL function entry point
00475 
00476   Label loop_entry, no_arguments, smi_argument, next_argument, wrong_call;
00477 
00478   char* entry_point = masm->pc();
00479   masm->set_last_Delta_frame_after_call();
00480   masm->pushl(0);                               // initial value for DLL state
00481   masm->movl(esi, esp);                         // save DLL state address
00482   masm->pushl(esp);                             // to check that the right no. of arguments is used
00483   if (TraceDLLCalls) {                          // call trace routine (C to C call, no special setup required)
00484     masm->pushl(esi);                           // save DLL state address
00485     masm->pushl(ebx);                           // pass arguments in reverse order
00486     masm->pushl(ecx);
00487     masm->pushl(edx);
00488     masm->call((char*)trace_DLL_call_1, relocInfo::runtime_call_type);
00489     masm->popl(edx);                            // restore registers
00490     masm->popl(ecx);
00491     masm->popl(ebx);
00492     masm->popl(esi);                            // restore DLL state address
00493   }
00494   masm->testl(ebx, ebx);                        // if number of arguments != 0 then
00495   masm->jcc(MacroAssembler::notZero, loop_entry);// convert arguments
00496 
00497   // done with all the arguments
00498   masm->bind(no_arguments);
00499   if (async) {
00500     masm->pushl(edx);
00501     masm->pushl(esi);                           // pass DLL state address
00502     masm->call((char*)DLLs::enter_async_call, relocInfo::runtime_call_type);
00503     masm->popl(esi);                            // discard argument
00504     masm->popl(edx);                            // restore registers
00505   }
00506 
00507   // do DLL call
00508   masm->call(edx);                              // eax := dll call (pops arguments itself)
00509 
00510   // check no. of arguments
00511   masm->popl(ebx);                              // must be the same as esp after popping
00512   masm->cmpl(ebx, esp);
00513   masm->jcc(Assembler::notEqual, wrong_call);
00514   
00515   // top of stack contains DLL state
00516   masm->movl(ebx, esp);                         // get DLL state address
00517   masm->pushl(eax);                             // save result
00518   masm->pushl(ebx);                             // pass DLL state address
00519   char* exit_dll = (char*)(async ? DLLs::exit_async_call : DLLs::exit_sync_call);
00520   masm->call(exit_dll, relocInfo::runtime_call_type);
00521   masm->popl(ebx);                              // discard argument
00522   masm->popl(eax);                              // restore result
00523 
00524   if (TraceDLLCalls) {                          // call trace routine (C to C call, no special setup required)
00525     masm->pushl(eax);                           // pass result
00526     masm->call((char*)trace_DLL_call_2, relocInfo::runtime_call_type);
00527     masm->popl(eax);                            // restore result
00528   }
00529   masm->popl(ebx);                              // discard DLL state word
00530   masm->reset_last_Delta_frame();
00531   masm->ret(0);
00532 
00533   // wrong DLL has been called (no. of popped arguments is incorrect)
00534   masm->bind(wrong_call);
00535   masm->call((char*)wrong_DLL_call, relocInfo::runtime_call_type);
00536   masm->hlt();                                  // should never reach here
00537 
00538   // smi argument -> convert it to int
00539   masm->bind(smi_argument);
00540   masm->sarl(eax, Tag_Size);                    // convert smi into C int
00541 
00542   // next argument
00543   masm->bind(next_argument);
00544   masm->pushl(eax);                             // push converted argument
00545   masm->addl(ecx, oopSize);                     // go to previous argument
00546   masm->decl(ebx);                              // decrement argument counter
00547   masm->jcc(MacroAssembler::zero, no_arguments);// continue until no arguments
00548 
00549   // loop
00550   masm->bind(loop_entry);
00551   // ebx: argument count
00552   // ecx: current argument address
00553   masm->movl(eax, Address(ecx));                // get argument
00554   masm->testb(eax, Mem_Tag);                    // check if smi or proxy
00555   masm->jcc(MacroAssembler::zero, smi_argument);
00556 
00557   // boxed argument -> unbox it
00558   masm->movl(eax, Address(eax, pointer_offset));// unbox proxy
00559   masm->jmp(next_argument);
00560 
00561   return entry_point;
00562 }
00563 
00564 
00565 char* StubRoutines::generate_lookup_DLL(MacroAssembler* masm, bool async) {
00566 // Lookup routine called from "empty" DLL caches in compiled code only.
00567 // Calls a lookup & patch routine which updates the DLL cache and then
00568 // continues with call_DLL.
00569 
00570   // ebx: number of arguments
00571   // ecx: address of last argument
00572   // edx: some initial value for DLL function entry point
00573   assert(call_DLL_entry(async) != NULL, "call_DLL_entry must have been generated before");
00574   char* entry_point = masm->pc();
00575   masm->set_last_Delta_frame_after_call();
00576   masm->pushl(ebx);                             // save registers (edx has no valid value yet)
00577   masm->pushl(ecx);
00578   masm->call((char*)DLLs::lookup_and_patch_CompiledDLL_Cache, relocInfo::runtime_call_type);    // eax := function entry point
00579   masm->popl(ecx);                              // restore registers
00580   masm->popl(ebx);
00581   masm->movl(edx, eax);                         // setup edx
00582   masm->reset_last_Delta_frame();
00583   masm->jmp(call_DLL_entry(async), relocInfo::runtime_call_type);       // now jump to real target
00584   return entry_point;
00585 }
00586 
00587 
00588 char* StubRoutines::generate_recompile_stub(MacroAssembler* masm) {
00589 // Recompilation; called by nmethod prologue of recompilation
00590 // trigger. Sets up stack frame and passes on receiver + caller
00591 // to C. Using the stub reduces the code size of nmethod prologues.
00592 
00593   // eax: receiver
00594   char* entry_point = masm->pc();
00595   //masm->int3();
00596   masm->set_last_Delta_frame_after_call();
00597   masm->call((char*)SavedRegisters::save_registers, relocInfo::runtime_call_type);
00598   masm->movl(ebx, Address(esp));                // get return address (trigger nmethod)
00599   masm->pushl(eax);                             // save receiver
00600   masm->pushl(ebx);                             // pass 2nd argument (pc)
00601   masm->pushl(eax);                             // pass 1st argument (recv)
00602   masm->call((char*)Recompilation::nmethod_invocation_counter_overflow, relocInfo::runtime_call_type);  // eax = nmethod_invocation_counter_overflow(receiver, pc)
00603   masm->movl(ecx, eax);                         // save continuation address in ecx
00604   masm->popl(eax);                              // pop 1st argument
00605   masm->popl(ebx);                              // pop 2nd argument
00606   masm->popl(eax);                              // restore receiver
00607   masm->reset_last_Delta_frame();
00608   masm->leave();                                // remove trigger nmethod's stack frame
00609   masm->jmp(ecx);                               // continue
00610   return entry_point;
00611 }
00612 
00613 
00614 /* Old code - keep around for a while - gri 9/18/96
00615 
00616 extern "C" char* recompileNMethod(oop rcvr, char* retpc);
00617 
00618 char* StubRoutines::generate_recompile_stub(MacroAssembler* masm) {
00619 // Recompilation; called by nmethod prologue of recompilation
00620 // trigger. Sets up stack frame and passes on receiver + caller
00621 // to C. Using the stub reduces the code size of nmethod prologues.
00622 
00623   char* entry_point = masm->pc();
00624   masm->movl(ebx, Address(esp));                // get return address (trigger nmethod)
00625   masm->enter();                                // create normal stack frame with link (for stub)
00626   masm->pushl(eax);                             // save receiver
00627   masm->call_C((char*)recompileNMethod, eax, ebx);      // eax = recompileNMethod(receiver, pc)
00628   masm->movl(ecx, eax);                         // save continuation address in ecx
00629   masm->popl(eax);                              // restore receiver
00630   masm->leave();                                // remove this stack frame
00631   masm->leave();                                // remove trigger's stack frame
00632   masm->jmp(ecx);                               // continue
00633   return entry_point;
00634 }
00635 */
00636 
00637 
00638 char* StubRoutines::generate_uncommon_trap(MacroAssembler* masm) {
00639   char* entry_point = masm->pc();
00640   masm->set_last_Delta_frame_after_call();
00641   masm->call((char*)SavedRegisters::save_registers, relocInfo::runtime_call_type);
00642   masm->call((char*)uncommon_trap, relocInfo::runtime_call_type);
00643   masm->reset_last_Delta_frame();
00644   masm->ret(0);
00645   return entry_point;
00646 }
00647 
00648 
00649 
00650 char* StubRoutines::generate_verify_context_chain(MacroAssembler* masm) {
00651 // Verify the context chain for a block nmethod, if there is
00652 // an unoptimized context in the chain the block must be deoptimized
00653 // and reevaluated.
00654 //
00655 // Called as first instruction for a block nmethod if 
00656 // the method is expecting a contextOop
00657 //
00658 // Stack at entry:
00659 //   [nmethod caller return address]  @ esp - 4
00660 //   [callee nmethod return address]  @ esp
00661 //
00662 // Registers at entry:
00663 //   ebp points to nmethod callers frame
00664 //   eax contains the block closure.
00665 
00666   Label deoptimize;
00667 
00668   char* entry_point = masm->pc();
00669   masm->set_last_Delta_frame_after_call();
00670   masm->pushl(self_reg); // pass argument (C calling convention)
00671   masm->call((char*)validateContextChain, relocInfo::runtime_call_type);
00672   masm->movl(ebx, eax);
00673   masm->popl(self_reg);
00674   masm->reset_last_Delta_frame();
00675   masm->testl(ebx,ebx);
00676   masm->jcc(MacroAssembler::zero, deoptimize);
00677   masm->ret(0);
00678 
00679   masm->bind(deoptimize);
00680   masm->addl(esp, 4);
00681   masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
00682   return entry_point;
00683 }
00684 
00685 
00686 static blockClosureOop deoptimize_block(blockClosureOop block) {
00687   VerifyNoAllocation vna;
00688   assert(block->is_block(),        "must be a block");
00689   assert(block->isCompiledBlock(), "we should be in a compiled block");
00690 
00691   #ifdef ASSERT
00692     // just checking if the context chain really contains an unoptimized context
00693     bool has_unoptimized_context = false;
00694     { contextOop con = block->lexical_scope();
00695       // verify entire context chain
00696       assert(con->is_context(), "expecting a context");
00697       while (true) {
00698         if (con->unoptimized_context() != NULL) {
00699           has_unoptimized_context = true;
00700           break;
00701         }
00702         if (!con->has_outer_context()) break; 
00703         con = con->outer_context();
00704       }
00705     }
00706     assert(has_unoptimized_context, "should have an unoptimized context");
00707   #endif
00708 
00709   block->deoptimize();
00710   return block;
00711 }
00712 
00713 
00714 char* StubRoutines::generate_deoptimize_block(MacroAssembler* masm) {
00715 // Called if there's an unoptimized context in the incoming context
00716 // chain of a block nmethod. The block must be deoptimized and the
00717 // value send has to be restarted.
00718 //
00719 // Called from block nmethods with incoming contexts, immediately
00720 // after checking the context chain and before any stack frame
00721 // has been set up.
00722 
00723   // eax: block closure
00724   // tos: callee nmethod return address (returning to caller)
00725   char* entry_point = masm->pc();
00726   masm->set_last_Delta_frame_after_call();      // nmethod is treated as C routine
00727   masm->pushl(self_reg);                        // pass argument
00728   masm->call((char*)deoptimize_block, relocInfo::runtime_call_type);    // eax := deoptimize_block(self_reg)
00729   masm->popl(ebx);                              // get rid of argument
00730   masm->reset_last_Delta_frame();               // return & restart the primitive (eax must contain the block)
00731   masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
00732   return entry_point;
00733 }
00734 
00735 
00736 char* StubRoutines::generate_call_inspector(MacroAssembler* masm) {
00737 // Called for each MacroAssembler::inspect(...) - used for debugging only
00738   char* entry_point = masm->pc();
00739   masm->set_last_Delta_frame_after_call();      // just in case somebody wants to look at the stack
00740   masm->pushad();
00741   masm->call((char*)MacroAssembler::inspector, relocInfo::runtime_call_type);
00742   masm->popad();
00743   masm->reset_last_Delta_frame();
00744   masm->ret(0);
00745   return entry_point;
00746 }
00747 
00748 
00749 char* StubRoutines::generate_PIC_stub(MacroAssembler* masm, int pic_size) {
00750 // Called from within a PIC (polymorphic inline cache).
00751 // The stub interprets the methodOop section of compiled PICs.
00752 // The methodOop section layout is as follows:
00753 //
00754 // call <this stub routine>
00755 // cached klass 1       <--- return address (tos)
00756 // cached methodOop 1
00757 // cached klass 2
00758 // cached methodOop2
00759 // ...
00760 //
00761 // cached klass n
00762 // cached methodOop n
00763 //
00764 // Note: Don't use this for polymorphic super sends!
00765 
00766   Label found, loop;
00767 
00768   // entry found at index
00769   //
00770   // eax: receiver
00771   // ebx: PIC table pointer
00772   // ecx: methodOop
00773   // edx: receiver klass
00774   // tos: return address of polymorphic send in compiled code
00775   masm->bind(found);
00776   masm->movl(edx, Address(int(&method_entry_point), relocInfo::external_word_type));
00777   // (Note: cannot use value in method_entry_point directly since interpreter is generated afterwards)
00778   masm->xorl(ebx, ebx);
00779   // eax: receiver
00780   // ebx: 000000xx
00781   // ecx: methodOop
00782   masm->jmp(edx);
00783 
00784   // eax    : receiver
00785   // tos    : return address pointing to table in PIC
00786   // tos + 4: return address of polymorphic send in compiled code
00787   // tos + 8: last argument/receiver
00788   char* entry_point = masm->pc();
00789   masm->popl(ebx);                              // get return address (PIC table pointer)
00790   masm->movl(edx, Address((int)&smiKlassObj, relocInfo::external_word_type));
00791   masm->test(eax, Mem_Tag);                     // check if smi
00792   masm->jcc(Assembler::zero, loop);             // if so, class is already in ecx
00793   masm->movl(edx, Address(eax, memOopDesc::klass_byte_offset()));       // otherwise, load receiver class
00794 
00795   // eax: receiver
00796   // ebx: PIC table pointer
00797   // edx: receiver klass
00798   // tos: return address of polymorphic send in compiled code
00799   masm->bind(loop);
00800   for (int i = 0; i < pic_size; i++) {
00801     // compare receiver klass with klass in PIC table at index
00802     masm->cmpl(edx, Address(ebx, i * PIC::PIC_methodOop_entry_size + PIC::PIC_methodOop_klass_offset));
00803     masm->movl(ecx, Address(ebx, i * PIC::PIC_methodOop_entry_size + PIC::PIC_methodOop_offset));
00804     masm->jcc(Assembler::equal, found);
00805   }
00806   assert(ic_normal_lookup_entry() != NULL, "ic_normal_lookup_entry must be generated before");
00807   masm->jmp(ic_normal_lookup_entry(), relocInfo::runtime_call_type);
00808 
00809   return entry_point;
00810 }
00811 
00812 
00813 char* StubRoutines::generate_allocate(MacroAssembler* masm, int size) {
00814   char* entry_point = masm->pc();
00815   masm->hlt();
00816   return entry_point;
00817 }
00818 
00819 
00820 // Parametrized accessors
00821 
00822 char* StubRoutines::PIC_stub_entry(int pic_size) {
00823   assert(_is_initialized, "StubRoutines not initialized yet");
00824   assert(1 <= pic_size && pic_size <= PIC::max_nof_entries, "pic size out of range")
00825   return _PIC_stub_entries[pic_size];
00826 }
00827 
00828 
00829 char* StubRoutines::allocate_entry(int size) {
00830   assert(_is_initialized, "StubRoutines not initialized yet");
00831   assert(0 <= size && size <= max_fast_allocate_size, "size out of range")
00832   return _allocate_entries[size];
00833 }
00834 
00835 
00836 // Initialization
00837 
00838 bool StubRoutines::_is_initialized = false;
00839 char StubRoutines::_code[StubRoutines::_code_size];
00840 
00841 char* StubRoutines::generate(MacroAssembler* masm, char* title, char* gen(MacroAssembler*)) {
00842   char* old_pc = masm->pc();
00843   char* entry_point = gen(masm);
00844   char* new_pc = masm->pc();
00845   if (!Disclaimer::is_product() && PrintStubRoutines) {
00846     std->print("Stub routine: %s", title);
00847     std->print(" (%d bytes), entry point = 0x%x\n", new_pc - old_pc, entry_point);
00848     masm->code()->decode();
00849     std->cr();
00850   }
00851   return entry_point;
00852 }
00853 
00854 
00855 char* StubRoutines::generate(MacroAssembler* masm, char* title, char* gen(MacroAssembler*, int argument), int argument) {
00856   char* old_pc = masm->pc();
00857   char* entry_point = gen(masm, argument);
00858   char* new_pc = masm->pc();
00859   if (!Disclaimer::is_product() && PrintStubRoutines) {
00860     std->print("Stub routine: %s %d", title, argument);
00861     std->print(" (%d bytes), entry point = 0x%x\n", new_pc - old_pc, entry_point);
00862     masm->code()->decode();
00863     std->cr();
00864   }
00865   return entry_point;
00866 }
00867 
00868 
00869 void StubRoutines::init() {
00870   if (_is_initialized) return;
00871 
00872   ResourceMark rm;
00873   CodeBuffer* code = new CodeBuffer(_code, _code_size);
00874   MacroAssembler* masm = new MacroAssembler(code);
00875 
00876   // add generators here
00877   _ic_normal_lookup_entry       = generate(masm, "ic_normal_lookup",     generate_ic_normal_lookup      );
00878   _ic_super_lookup_entry        = generate(masm, "ic_super_lookup",      generate_ic_super_lookup       );
00879   _zombie_nmethod_entry         = generate(masm, "zombie_nmethod",       generate_zombie_nmethod        );
00880   _zombie_block_nmethod_entry   = generate(masm, "zombie_block_nmethod", generate_zombie_block_nmethod  );
00881   _megamorphic_ic_entry         = generate(masm, "megamorphic_ic",       generate_megamorphic_ic        );
00882   _compile_block_entry          = generate(masm, "compile_block",        generate_compile_block         );
00883   _continue_NLR_entry           = generate(masm, "continue_NLR",         generate_continue_NLR          );
00884   _call_sync_DLL_entry          = generate(masm, "call_sync_DLL",        generate_call_sync_DLL         );
00885   _call_async_DLL_entry         = generate(masm, "call_async_DLL",       generate_call_async_DLL        );
00886   _lookup_sync_DLL_entry        = generate(masm, "lookup_sync_DLL",      generate_lookup_sync_DLL       );
00887   _lookup_async_DLL_entry       = generate(masm, "lookup_async_DLL",     generate_lookup_async_DLL      );
00888   _recompile_stub_entry         = generate(masm, "recompile_stub",       generate_recompile_stub        );
00889   _used_uncommon_trap_entry     = generate(masm, "used_uncommon_trap",   generate_uncommon_trap         );
00890   _unused_uncommon_trap_entry   = generate(masm, "unused_uncommon_trap", generate_uncommon_trap         );
00891   _verify_context_chain_entry   = generate(masm, "verify_context_chain", generate_verify_context_chain  );
00892   _deoptimize_block_entry       = generate(masm, "deoptimize_block",     generate_deoptimize_block      );
00893   _call_inspector_entry         = generate(masm, "call_inspector",       generate_call_inspector        );
00894 
00895   for (int pic_size = 1; pic_size <= PIC::max_nof_entries; pic_size++) {
00896     _PIC_stub_entries[pic_size] = generate(masm, "PIC stub", generate_PIC_stub, pic_size);
00897   }
00898 
00899   for (int size = 0; size <= max_fast_allocate_size; size++) {
00900     _allocate_entries[size] = generate(masm, "allocate", generate_allocate, size);
00901   }
00902 
00903   masm->finalize();
00904   _is_initialized = true;
00905   if (!Disclaimer::is_product() && PrintStubRoutines) {
00906     std->print("%d bytes generated for stub routines\n", masm->offset());
00907     exit(0);
00908   }
00909 };
00910 
00911 
00912 void stubRoutines_init() {
00913   StubRoutines::init();
00914 }

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