made a copy
[strongtalk-kjk.git] / vm / code / stubRoutines.cpp
blob5473ce666079e46f9382b622d75e60c636b34c65
1 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.44 $ */
2 /* Copyright (c) 2006, Sun Microsystems, Inc.
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
6 following conditions are met:
8 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
10 disclaimer in the documentation and/or other materials provided with the distribution.
11 * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived
12 from this software without specific prior written permission.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
15 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
16 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
19 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
25 # include "incls/_precompiled.incl"
26 # include "incls/_stubRoutines.cpp.incl"
28 const int max_fast_allocate_size = 9;
30 // entry points
31 char* StubRoutines::_ic_normal_lookup_entry = NULL;
32 char* StubRoutines::_ic_super_lookup_entry = NULL;
33 char* StubRoutines::_zombie_nmethod_entry = NULL;
34 char* StubRoutines::_zombie_block_nmethod_entry = NULL;
35 char* StubRoutines::_megamorphic_ic_entry = NULL;
36 char* StubRoutines::_compile_block_entry = NULL;
37 char* StubRoutines::_continue_NLR_entry = NULL;
38 char* StubRoutines::_call_sync_DLL_entry = NULL;
39 char* StubRoutines::_call_async_DLL_entry = NULL;
40 char* StubRoutines::_lookup_sync_DLL_entry = NULL;
41 char* StubRoutines::_lookup_async_DLL_entry = NULL;
42 char* StubRoutines::_recompile_stub_entry = NULL;
43 char* StubRoutines::_used_uncommon_trap_entry = NULL;
44 char* StubRoutines::_unused_uncommon_trap_entry = NULL;
45 char* StubRoutines::_verify_context_chain_entry = NULL;
46 char* StubRoutines::_deoptimize_block_entry = NULL;
47 char* StubRoutines::_call_inspector_entry = NULL;
49 char* StubRoutines::_PIC_stub_entries[PIC::max_nof_entries + 1]; // entry 0 ignored
50 char* StubRoutines::_allocate_entries[max_fast_allocate_size + 1];
53 // tracing
55 void StubRoutines::trace_DLL_call_1(dll_func function, oop* last_argument, int nof_arguments) {
56 if (!TraceDLLCalls) return; // in case it has been turned off during run-time
57 frame f = DeltaProcess::active()->last_frame();
58 if (f.is_interpreted_frame()) {
59 // called from within interpreter -> InterpretedDLL_Cache available
60 methodOop m = f.method();
61 CodeIterator it(m, m->bci_from(f.hp()));
62 InterpretedDLL_Cache* cache = it.dll_cache();
63 assert(cache->entry_point() == function, "inconsistency with InterpretedDLL_Cache");
64 assert(cache->number_of_arguments() == nof_arguments, "inconsistency with InterpretedDLL_Cache");
65 cache->print();
66 } else {
67 // called from within compiled code -> CompiledDLL_Cache available
68 CompiledDLL_Cache* cache = compiledDLL_Cache_from_return_address(f.pc());
69 assert(cache->entry_point() == function, "inconsistency with CompiledDLL_Cache");
70 cache->print();
72 // print arguments
73 int i = 1;
74 oop* arg_ptr = last_argument + (nof_arguments - 1);
75 for (i = 1; i <= nof_arguments; i++, arg_ptr--) {
76 oop arg = *arg_ptr;
77 std->print("%6d. ", i);
78 if (arg->is_smi()) {
79 std->print("smi value = %d\n", ((smiOop)arg)->value());
80 } else {
81 std->print("proxy value = 0x%08x (proxy = 0x%08x)\n", ((proxyOop)arg)->get_pointer(), arg);
87 void StubRoutines::trace_DLL_call_2(int result) {
88 if (!TraceDLLCalls) return; // in case it has been turned off during run-time
89 std->print(" result = 0x%08x\n", result);
93 void StubRoutines::wrong_DLL_call() {
94 { ResourceMark rm;
95 std->print("DLL call error: number of arguments probably wrong\n");
97 if (DeltaProcess::active()->is_scheduler()) {
98 DeltaProcess::active()->trace_stack();
99 fatal("DLL error in scheduler");
100 } else {
101 DeltaProcess::active()->suspend(::DLL_lookup_error);
103 ShouldNotReachHere();
107 // generators
109 char* StubRoutines::generate_ic_lookup(MacroAssembler* masm, char* lookup_routine_entry) {
110 // Stub routine that calls icLookup which patches the icache.
111 // After returning from icLookup the send is continued. The
112 // icLookupStub is called from empty iCaches within compiled
113 // code.
115 // Note that so far, the lookup routine doesn't do allocation,
116 // therefore the receiver can be saved/restored on the C stack.
117 // (This has to be fixed as soon as 'message not understood' is
118 // handled correctly from within compiled code.
120 // eax: receiver
121 // tos: return address
122 char* entry_point = masm->pc();
123 masm->set_last_Delta_frame_after_call();
124 masm->movl(ebx, Address(esp)); // get return address (= ic address)
125 masm->pushl(eax); // save receiver
126 masm->pushl(ebx); // pass ic
127 masm->pushl(eax); // pass receiver
128 masm->call(lookup_routine_entry, relocInfo::runtime_call_type); // eax = lookup_routine(receiver, ic)
129 masm->movl(ebx, eax); // ebx = method code
130 masm->popl(eax); // get rid of receiver argument
131 masm->popl(eax); // get rid of ic argument
132 masm->popl(eax); // restore receiver (don't use argument, might be overwritten)
133 masm->reset_last_Delta_frame();
134 masm->jmp(ebx); // jump to target
135 return entry_point;
139 extern "C" char* icNormalLookup(oop recv, CompiledIC* ic);
140 extern "C" char* icSuperLookup (oop recv, CompiledIC* ic);
141 extern "C" char* zombie_nmethod(CompiledIC* ic);
143 char* StubRoutines::generate_ic_normal_lookup(MacroAssembler* masm) {
144 return generate_ic_lookup(masm, (char*)icNormalLookup);
148 char* StubRoutines::generate_ic_super_lookup(MacroAssembler* masm) {
149 return generate_ic_lookup(masm, (char*)icSuperLookup);
153 char* StubRoutines::generate_zombie_nmethod(MacroAssembler* masm) {
154 // Called from zombie nmethods immediately after they are called.
155 // Does cleanup of interpreted/compiled ic and redoes the send.
157 // Note: zombie_nmethod() doesn't do scavenge (otherwise this code
158 // has to change - the receiver cannot be saved on the stack).
160 // eax : receiver
161 // tos : return address to zombie nmethod (which called this stub)
162 // tos-4: return address to caller nmethod (which called the zombie nmethod)
163 char* entry_point = masm->pc();
164 masm->popl(ebx); // get rid of return address to zombie nmethod
165 // eax: receiver
166 // tos: return address to caller nmethod (which called the zombie nmethod)
167 masm->set_last_Delta_frame_after_call();
168 masm->movl(ebx, Address(esp)); // get return address (= ic address) - don't pop! (needed for correct Delta frame)
169 masm->pushl(eax); // save receiver
170 masm->pushl(ebx); // pass ic
171 masm->call((char*)zombie_nmethod, relocInfo::runtime_call_type); // eax = zombie_nmethod(return_address)
172 masm->movl(ecx, eax); // ecx = entry point to redo send
173 masm->popl(ebx); // get rid of ic argument
174 masm->popl(eax); // restore receiver
175 masm->popl(ebx); // get rid of return address
176 masm->reset_last_Delta_frame();
177 masm->jmp(ecx); // redo send
178 return entry_point;
181 // The code below (validateContextChain(...) and generate_verify_context_chain(...)
182 // can be removed if it turns out that the new solution (using deoptimize_block()
183 // and generate_deoptimize_block(...)) is working correctly. See also call site
184 // (code for PrologueNode). - gri 6/25/96
186 static bool validateContextChain(blockClosureOop block) {
187 assert(block->is_block(), "must be block");
188 bool is_valid = true;
190 { contextOop con = block->lexical_scope();
191 // verify entire context chain
192 assert(con->is_context(), "expecting a context");
194 while (true) {
195 if (con->unoptimized_context() != NULL) {
196 is_valid = false;
197 break;
199 if (!con->has_outer_context()) break;
200 con = con->outer_context();
204 if (is_valid) return true;
206 assert(block->isCompiledBlock(), "we should be in a compiled block");
208 // Patch the blockClosure
209 methodOop method = block->method();
210 nmethod* nm = block->jump_table_entry()->block_nmethod();
212 LOG_EVENT1("Deoptimized context in blockClosure -> switch to methodOop 0x%lx", nm);
214 block->set_method(method);
215 contextOop con = block->lexical_scope();
216 contextOop un_con = con->unoptimized_context();
217 if (un_con) {
218 block->set_lexical_scope(un_con);
219 } else {
220 Unimplemented();
223 return false;
226 static void deoptimize_context_and_patch_block(blockClosureOop block) {
227 assert(block->is_block(), "must be block");
228 assert(block->isCompiledBlock(), "we should be in a compiled block");
230 // Patch the blockClosure
231 methodOop method = block->method();
232 nmethod* nm = block->jump_table_entry()->block_nmethod();
234 LOG_EVENT1("Deoptimized context in blockClosure -> switch to methodOop 0x%lx", nm);
236 contextOop con = block->lexical_scope();
237 block->set_method(method);
238 if (method->expectsContext()) {
239 guarantee(con && con->is_context(), "Optimized context must be present");
241 // we have (nm, con) the deoptimize the context
242 contextOop unoptimized_con = con->unoptimized_context();
243 guarantee(unoptimized_con && unoptimized_con->is_context(), "Unoptimized context must be present");
244 block->set_lexical_scope(unoptimized_con);
245 } else {
246 guarantee(!con->is_context(), "Cannot be a context");
250 extern "C" void restart_primitiveValue();
252 char* StubRoutines::generate_zombie_block_nmethod(MacroAssembler* masm) {
253 // Called from zombie nmethods immediately after they are called.
254 // Does cleanup of interpreted/compiled ic and redoes the send.
256 // Note: zombie_nmethod() doesn't do scavenge (otherwise this code
257 // has to change - the receiver cannot be saved on the stack).
259 // eax : receiver
260 // tos : return address to zombie nmethod (which called this stub)
261 // tos-4: return address to caller nmethod (which called the zombie nmethod)
262 char* entry_point = masm->pc();
264 masm->set_last_Delta_frame_after_call();
265 masm->pushl(self_reg); // pass argument (C calling convention)
266 masm->call((char*)deoptimize_context_and_patch_block, relocInfo::runtime_call_type);
267 masm->movl(ebx, eax);
268 masm->popl(self_reg);
269 masm->reset_last_Delta_frame();
270 masm->addl(esp, 4);
271 masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
272 return entry_point;
275 extern "C" char* method_entry_point;
277 char* StubRoutines::generate_megamorphic_ic(MacroAssembler* masm) {
278 // Called from within a MIC (megamorphic inline cache), the special
279 // variant of PICs for compiled code (see compiledPIC.hpp/cpp).
280 // The MIC layout is as follows:
282 // call <this stub routine>
283 // selector <--- return address (tos)
285 // Note: Don't use this for megamorphic super sends!
287 Label is_smi, probe_primary_cache, probe_secondary_cache, call_method, is_methodOop, do_lookup;
289 masm->bind(is_smi); // smi case (assumed to be infrequent)
290 masm->movl(ecx, Address((int)&smiKlassObj, relocInfo::external_word_type));
291 masm->jmp(probe_primary_cache);
293 // eax : receiver
294 // tos : return address pointing to selector in MIC
295 // tos + 4: return address of megamorphic send in compiled code
296 // tos + 8: last argument/receiver
297 char* entry_point = masm->pc();
298 masm->popl(ebx); // get return address (MIC cache)
299 masm->test(eax, Mem_Tag); // check if smi
300 masm->jcc(Assembler::zero, is_smi); // if so, get smi class directly
301 masm->movl(ecx, Address(eax, memOopDesc::klass_byte_offset())); // otherwise, load receiver class
303 // probe primary cache
305 // eax: receiver
306 // ebx: MIC cache pointer
307 // ecx: receiver klass
308 // tos: return address of megamorphic send in compiled code (ic)
309 masm->bind(probe_primary_cache); // compute hash value
310 masm->movl(edx, Address(ebx)); // get selector
311 // compute hash value
312 masm->movl(edi, ecx);
313 masm->xorl(edi, edx);
314 masm->andl(edi, (primary_cache_size - 1) << 4);
315 // probe cache
316 masm->cmpl(ecx, Address(edi, lookupCache::primary_cache_address() + 0*oopSize));
317 masm->jcc(Assembler::notEqual, probe_secondary_cache);
318 masm->cmpl(edx, Address(edi, lookupCache::primary_cache_address() + 1*oopSize));
319 masm->jcc(Assembler::notEqual, probe_secondary_cache);
320 masm->movl(ecx, Address(edi, lookupCache::primary_cache_address() + 2*oopSize));
322 // call method
324 // eax: receiver
325 // ecx: methodOop/nmethod
326 // tos: return address of megamorphic send in compiled code (ic)
327 masm->bind(call_method);
328 masm->test(ecx, Mem_Tag); // check if methodOop
329 masm->jcc(Assembler::notZero, is_methodOop); // otherwise
330 masm->jmp(ecx); // call nmethod
332 // call methodOop - setup registers
333 masm->bind(is_methodOop);
334 masm->xorl(ebx, ebx); // clear ebx for interpreter
335 masm->movl(edx, Address(int(&method_entry_point), relocInfo::external_word_type));
336 // (Note: cannot use value in method_entry_point directly since interpreter is generated afterwards)
338 // eax: receiver
339 // ebx: 00000000
340 // ecx: methodOop
341 // edx: entry point
342 // tos: return address of megamorphic send in compiled code (ic)
343 masm->jmp(edx); // call method_entry
345 // probe secondary cache
347 // eax: receiver
348 // ebx: MIC cache pointer
349 // ecx: receiver klass
350 // edx: selector
351 // edi: primary cache index
352 // tos: return address of megamorphic send in compiled code (ic)
353 masm->bind(probe_secondary_cache); // compute hash value
354 masm->andl(edi, (secondary_cache_size - 1) << 4);
355 // probe cache
356 masm->cmpl(ecx, Address(edi, lookupCache::secondary_cache_address() + 0*oopSize));
357 masm->jcc(Assembler::notEqual, do_lookup);
358 masm->cmpl(edx, Address(edi, lookupCache::secondary_cache_address() + 1*oopSize));
359 masm->jcc(Assembler::notEqual, do_lookup);
360 masm->movl(ecx, Address(edi, lookupCache::secondary_cache_address() + 2*oopSize));
361 masm->jmp(call_method);
363 // do lookup
365 // eax: receiver
366 // ebx: MIC cache pointer
367 // ecx: receiver klass
368 // edx: selector
369 // edi: secondary cache index
370 // tos: return address of megamorphic send in compiled code (ic)
371 masm->bind(do_lookup);
372 masm->set_last_Delta_frame_after_call();
373 masm->pushl(eax); // save receiver
374 masm->pushl(edx); // pass 2nd argument: selector
375 masm->pushl(ecx); // pass 1st argument: receiver klass
376 masm->call((char*)lookupCache::normal_lookup, relocInfo::runtime_call_type);
377 masm->movl(ecx, eax); // ecx: method
378 masm->popl(ebx); // pop 1st argument
379 masm->popl(ebx); // pop 2nd argument
380 masm->popl(eax); // restore receiver
381 masm->reset_last_Delta_frame();
382 masm->testl(ecx, ecx); // test if method has been found in lookup cache
383 masm->jcc(Assembler::notZero, call_method);
385 // method not found in the lookup cache - full lookup needed (message not understood may happen)
386 // eax: receiver
387 // ebx: points to MIC cache
388 // tos: return address of megamorphic send in compiled code
390 // Note: This should not happen right now, since normal_lookup always returns a value
391 // if the method exists (and 'message not understood' is not yet supported in
392 // compiled code). However, this should change at some point, and normal_lookup_cache_probe
393 // should be used instead of normal_lookup.
394 masm->hlt();
396 return entry_point;
400 char* StubRoutines::generate_compile_block(MacroAssembler* masm) {
401 // Stub routine that is called from a jumptable entry for a block closure.
402 // The recipe:
403 // - compile the toplevelblock nmethod
404 // - patch the jump entry with the entry point of the compiler nmethod
405 // - jump to the new nmethod.
407 // Note that compile_new_block doesn't do allocation,
408 // therefore the receiver can be saved on the C stack.
410 // eax: receiver
411 char* entry_point = masm->pc();
412 masm->set_last_Delta_frame_after_call();
413 masm->pushl(eax); // save receiver
414 masm->pushl(eax); // pass receiver
415 masm->call((char*)jumpTable::compile_new_block, relocInfo::runtime_call_type); // eax = block_closure_compile(receiver)
416 masm->movl(ebx, eax); // ebx = block code
417 masm->popl(eax); // get rid of receiver argument
418 masm->popl(eax); // restore receiver (don't use argument, might be overwritten)
419 masm->reset_last_Delta_frame();
420 masm->jmp(ebx); // jump to target
421 return entry_point;
425 char* StubRoutines::generate_continue_NLR(MacroAssembler* masm) {
426 // Entry point jumped to from compiled code. Initiates (or continues an ongoing) NLR.
427 // Originally this code has been generated in nmethods, using a stub reduces code size.
429 Register ret_addr = temp1;
430 Register offset = temp2;
432 char* entry_point = masm->pc();
433 masm->leave(); // remove stack frame
434 masm->popl(ret_addr); // get (local) return address
435 masm->movl(offset, Address(ret_addr, IC_Info::info_offset)); // get ic info
436 if (IC_Info::number_of_flags > 0) {
437 masm->sarl(offset, IC_Info::number_of_flags); // shift ic info flags out
439 masm->addl(ret_addr, offset); // compute non-local return address
440 masm->jmp(ret_addr); // do NLR
441 return entry_point;
445 char* StubRoutines::generate_call_DLL(MacroAssembler* masm, bool async) {
446 // The following routine provides the extra frame for DLL calls.
447 // Note: 1. Its code has to be *outside* the interpreters code! (see also: DLL calls in interpreter)
448 // 2. This routine is also used by the compiler! Make sure to adjust the parameter
449 // passing in the compiler as well (x86_node.cpp, codeGenerator.cpp), when changing this code!
451 // Stack layout immediately after calling the DLL:
452 // (The DLL state word is used for asynchronous DLL/interrupted DLL calls)
454 // ... DLL land
455 // esp->[ return addr ] ------------------------------------------------------------------------
456 // [ unboxed arg 1 ] C land
457 // ...
458 // [ unboxed arg n ]
459 // [ ptr to itself ] <---- ptr to itself to check that the right no. of arguments is used
460 // [ DLL state ] used for DLL/interrupted DLL calls
461 // [ return addr ] ------------------------------------------------------------------------
462 // [ argument n ] <---- last_Delta_sp Delta land
463 // [ argument n-1 ]
464 // ...
465 // [ argument 1 ]
466 // [ return proxy ]
467 // ...
468 // ebp->[ previous ebp ] <---- last_Delta_fp
470 // The routine expects 3 arguments to be passed in registers as follows:
472 // ebx: number of arguments
473 // ecx: address of last argument
474 // edx: DLL function entry point
476 Label loop_entry, no_arguments, smi_argument, next_argument, wrong_call;
478 char* entry_point = masm->pc();
479 masm->set_last_Delta_frame_after_call();
480 masm->pushl(0); // initial value for DLL state
481 masm->movl(esi, esp); // save DLL state address
482 masm->pushl(esp); // to check that the right no. of arguments is used
483 if (TraceDLLCalls) { // call trace routine (C to C call, no special setup required)
484 masm->pushl(esi); // save DLL state address
485 masm->pushl(ebx); // pass arguments in reverse order
486 masm->pushl(ecx);
487 masm->pushl(edx);
488 masm->call((char*)trace_DLL_call_1, relocInfo::runtime_call_type);
489 masm->popl(edx); // restore registers
490 masm->popl(ecx);
491 masm->popl(ebx);
492 masm->popl(esi); // restore DLL state address
494 masm->testl(ebx, ebx); // if number of arguments != 0 then
495 masm->jcc(MacroAssembler::notZero, loop_entry);// convert arguments
497 // done with all the arguments
498 masm->bind(no_arguments);
499 if (async) {
500 masm->pushl(edx);
501 masm->pushl(esi); // pass DLL state address
502 masm->call((char*)DLLs::enter_async_call, relocInfo::runtime_call_type);
503 masm->popl(esi); // discard argument
504 masm->popl(edx); // restore registers
507 // do DLL call
508 masm->call(edx); // eax := dll call (pops arguments itself)
510 // check no. of arguments
511 masm->popl(ebx); // must be the same as esp after popping
512 masm->cmpl(ebx, esp);
513 masm->jcc(Assembler::notEqual, wrong_call);
515 // top of stack contains DLL state
516 masm->movl(ebx, esp); // get DLL state address
517 masm->pushl(eax); // save result
518 masm->pushl(ebx); // pass DLL state address
519 char* exit_dll = (char*)(async ? DLLs::exit_async_call : DLLs::exit_sync_call);
520 masm->call(exit_dll, relocInfo::runtime_call_type);
521 masm->popl(ebx); // discard argument
522 masm->popl(eax); // restore result
524 if (TraceDLLCalls) { // call trace routine (C to C call, no special setup required)
525 masm->pushl(eax); // pass result
526 masm->call((char*)trace_DLL_call_2, relocInfo::runtime_call_type);
527 masm->popl(eax); // restore result
529 masm->popl(ebx); // discard DLL state word
530 masm->reset_last_Delta_frame();
531 masm->ret(0);
533 // wrong DLL has been called (no. of popped arguments is incorrect)
534 masm->bind(wrong_call);
535 masm->call((char*)wrong_DLL_call, relocInfo::runtime_call_type);
536 masm->hlt(); // should never reach here
538 // smi argument -> convert it to int
539 masm->bind(smi_argument);
540 masm->sarl(eax, Tag_Size); // convert smi into C int
542 // next argument
543 masm->bind(next_argument);
544 masm->pushl(eax); // push converted argument
545 masm->addl(ecx, oopSize); // go to previous argument
546 masm->decl(ebx); // decrement argument counter
547 masm->jcc(MacroAssembler::zero, no_arguments);// continue until no arguments
549 // loop
550 masm->bind(loop_entry);
551 // ebx: argument count
552 // ecx: current argument address
553 masm->movl(eax, Address(ecx)); // get argument
554 masm->testb(eax, Mem_Tag); // check if smi or proxy
555 masm->jcc(MacroAssembler::zero, smi_argument);
557 // boxed argument -> unbox it
558 masm->movl(eax, Address(eax, pointer_offset));// unbox proxy
559 masm->jmp(next_argument);
561 return entry_point;
565 char* StubRoutines::generate_lookup_DLL(MacroAssembler* masm, bool async) {
566 // Lookup routine called from "empty" DLL caches in compiled code only.
567 // Calls a lookup & patch routine which updates the DLL cache and then
568 // continues with call_DLL.
570 // ebx: number of arguments
571 // ecx: address of last argument
572 // edx: some initial value for DLL function entry point
573 assert(call_DLL_entry(async) != NULL, "call_DLL_entry must have been generated before");
574 char* entry_point = masm->pc();
575 masm->set_last_Delta_frame_after_call();
576 masm->pushl(ebx); // save registers (edx has no valid value yet)
577 masm->pushl(ecx);
578 masm->call((char*)DLLs::lookup_and_patch_CompiledDLL_Cache, relocInfo::runtime_call_type); // eax := function entry point
579 masm->popl(ecx); // restore registers
580 masm->popl(ebx);
581 masm->movl(edx, eax); // setup edx
582 masm->reset_last_Delta_frame();
583 masm->jmp(call_DLL_entry(async), relocInfo::runtime_call_type); // now jump to real target
584 return entry_point;
588 char* StubRoutines::generate_recompile_stub(MacroAssembler* masm) {
589 // Recompilation; called by nmethod prologue of recompilation
590 // trigger. Sets up stack frame and passes on receiver + caller
591 // to C. Using the stub reduces the code size of nmethod prologues.
593 // eax: receiver
594 char* entry_point = masm->pc();
595 //masm->int3();
596 masm->set_last_Delta_frame_after_call();
597 masm->call((char*)SavedRegisters::save_registers, relocInfo::runtime_call_type);
598 masm->movl(ebx, Address(esp)); // get return address (trigger nmethod)
599 masm->pushl(eax); // save receiver
600 masm->pushl(ebx); // pass 2nd argument (pc)
601 masm->pushl(eax); // pass 1st argument (recv)
602 masm->call((char*)Recompilation::nmethod_invocation_counter_overflow, relocInfo::runtime_call_type); // eax = nmethod_invocation_counter_overflow(receiver, pc)
603 masm->movl(ecx, eax); // save continuation address in ecx
604 masm->popl(eax); // pop 1st argument
605 masm->popl(ebx); // pop 2nd argument
606 masm->popl(eax); // restore receiver
607 masm->reset_last_Delta_frame();
608 masm->leave(); // remove trigger nmethod's stack frame
609 masm->jmp(ecx); // continue
610 return entry_point;
614 /* Old code - keep around for a while - gri 9/18/96
616 extern "C" char* recompileNMethod(oop rcvr, char* retpc);
618 char* StubRoutines::generate_recompile_stub(MacroAssembler* masm) {
619 // Recompilation; called by nmethod prologue of recompilation
620 // trigger. Sets up stack frame and passes on receiver + caller
621 // to C. Using the stub reduces the code size of nmethod prologues.
623 char* entry_point = masm->pc();
624 masm->movl(ebx, Address(esp)); // get return address (trigger nmethod)
625 masm->enter(); // create normal stack frame with link (for stub)
626 masm->pushl(eax); // save receiver
627 masm->call_C((char*)recompileNMethod, eax, ebx); // eax = recompileNMethod(receiver, pc)
628 masm->movl(ecx, eax); // save continuation address in ecx
629 masm->popl(eax); // restore receiver
630 masm->leave(); // remove this stack frame
631 masm->leave(); // remove trigger's stack frame
632 masm->jmp(ecx); // continue
633 return entry_point;
638 char* StubRoutines::generate_uncommon_trap(MacroAssembler* masm) {
639 char* entry_point = masm->pc();
640 masm->set_last_Delta_frame_after_call();
641 masm->call((char*)SavedRegisters::save_registers, relocInfo::runtime_call_type);
642 masm->call((char*)uncommon_trap, relocInfo::runtime_call_type);
643 masm->reset_last_Delta_frame();
644 masm->ret(0);
645 return entry_point;
650 char* StubRoutines::generate_verify_context_chain(MacroAssembler* masm) {
651 // Verify the context chain for a block nmethod, if there is
652 // an unoptimized context in the chain the block must be deoptimized
653 // and reevaluated.
655 // Called as first instruction for a block nmethod if
656 // the method is expecting a contextOop
658 // Stack at entry:
659 // [nmethod caller return address] @ esp - 4
660 // [callee nmethod return address] @ esp
662 // Registers at entry:
663 // ebp points to nmethod callers frame
664 // eax contains the block closure.
666 Label deoptimize;
668 char* entry_point = masm->pc();
669 masm->set_last_Delta_frame_after_call();
670 masm->pushl(self_reg); // pass argument (C calling convention)
671 masm->call((char*)validateContextChain, relocInfo::runtime_call_type);
672 masm->movl(ebx, eax);
673 masm->popl(self_reg);
674 masm->reset_last_Delta_frame();
675 masm->testl(ebx,ebx);
676 masm->jcc(MacroAssembler::zero, deoptimize);
677 masm->ret(0);
679 masm->bind(deoptimize);
680 masm->addl(esp, 4);
681 masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
682 return entry_point;
686 static blockClosureOop deoptimize_block(blockClosureOop block) {
687 VerifyNoAllocation vna;
688 assert(block->is_block(), "must be a block");
689 assert(block->isCompiledBlock(), "we should be in a compiled block");
691 #ifdef ASSERT
692 // just checking if the context chain really contains an unoptimized context
693 bool has_unoptimized_context = false;
694 { contextOop con = block->lexical_scope();
695 // verify entire context chain
696 assert(con->is_context(), "expecting a context");
697 while (true) {
698 if (con->unoptimized_context() != NULL) {
699 has_unoptimized_context = true;
700 break;
702 if (!con->has_outer_context()) break;
703 con = con->outer_context();
706 assert(has_unoptimized_context, "should have an unoptimized context");
707 #endif
709 block->deoptimize();
710 return block;
714 char* StubRoutines::generate_deoptimize_block(MacroAssembler* masm) {
715 // Called if there's an unoptimized context in the incoming context
716 // chain of a block nmethod. The block must be deoptimized and the
717 // value send has to be restarted.
719 // Called from block nmethods with incoming contexts, immediately
720 // after checking the context chain and before any stack frame
721 // has been set up.
723 // eax: block closure
724 // tos: callee nmethod return address (returning to caller)
725 char* entry_point = masm->pc();
726 masm->set_last_Delta_frame_after_call(); // nmethod is treated as C routine
727 masm->pushl(self_reg); // pass argument
728 masm->call((char*)deoptimize_block, relocInfo::runtime_call_type); // eax := deoptimize_block(self_reg)
729 masm->popl(ebx); // get rid of argument
730 masm->reset_last_Delta_frame(); // return & restart the primitive (eax must contain the block)
731 masm->jmp((char*)restart_primitiveValue, relocInfo::runtime_call_type);
732 return entry_point;
736 char* StubRoutines::generate_call_inspector(MacroAssembler* masm) {
737 // Called for each MacroAssembler::inspect(...) - used for debugging only
738 char* entry_point = masm->pc();
739 masm->set_last_Delta_frame_after_call(); // just in case somebody wants to look at the stack
740 masm->pushad();
741 masm->call((char*)MacroAssembler::inspector, relocInfo::runtime_call_type);
742 masm->popad();
743 masm->reset_last_Delta_frame();
744 masm->ret(0);
745 return entry_point;
749 char* StubRoutines::generate_PIC_stub(MacroAssembler* masm, int pic_size) {
750 // Called from within a PIC (polymorphic inline cache).
751 // The stub interprets the methodOop section of compiled PICs.
752 // The methodOop section layout is as follows:
754 // call <this stub routine>
755 // cached klass 1 <--- return address (tos)
756 // cached methodOop 1
757 // cached klass 2
758 // cached methodOop2
759 // ...
761 // cached klass n
762 // cached methodOop n
764 // Note: Don't use this for polymorphic super sends!
766 Label found, loop;
768 // entry found at index
770 // eax: receiver
771 // ebx: PIC table pointer
772 // ecx: methodOop
773 // edx: receiver klass
774 // tos: return address of polymorphic send in compiled code
775 masm->bind(found);
776 masm->movl(edx, Address(int(&method_entry_point), relocInfo::external_word_type));
777 // (Note: cannot use value in method_entry_point directly since interpreter is generated afterwards)
778 masm->xorl(ebx, ebx);
779 // eax: receiver
780 // ebx: 000000xx
781 // ecx: methodOop
782 masm->jmp(edx);
784 // eax : receiver
785 // tos : return address pointing to table in PIC
786 // tos + 4: return address of polymorphic send in compiled code
787 // tos + 8: last argument/receiver
788 char* entry_point = masm->pc();
789 masm->popl(ebx); // get return address (PIC table pointer)
790 masm->movl(edx, Address((int)&smiKlassObj, relocInfo::external_word_type));
791 masm->test(eax, Mem_Tag); // check if smi
792 masm->jcc(Assembler::zero, loop); // if so, class is already in ecx
793 masm->movl(edx, Address(eax, memOopDesc::klass_byte_offset())); // otherwise, load receiver class
795 // eax: receiver
796 // ebx: PIC table pointer
797 // edx: receiver klass
798 // tos: return address of polymorphic send in compiled code
799 masm->bind(loop);
800 for (int i = 0; i < pic_size; i++) {
801 // compare receiver klass with klass in PIC table at index
802 masm->cmpl(edx, Address(ebx, i * PIC::PIC_methodOop_entry_size + PIC::PIC_methodOop_klass_offset));
803 masm->movl(ecx, Address(ebx, i * PIC::PIC_methodOop_entry_size + PIC::PIC_methodOop_offset));
804 masm->jcc(Assembler::equal, found);
806 assert(ic_normal_lookup_entry() != NULL, "ic_normal_lookup_entry must be generated before");
807 masm->jmp(ic_normal_lookup_entry(), relocInfo::runtime_call_type);
809 return entry_point;
813 char* StubRoutines::generate_allocate(MacroAssembler* masm, int size) {
814 char* entry_point = masm->pc();
815 masm->hlt();
816 return entry_point;
820 // Parametrized accessors
822 char* StubRoutines::PIC_stub_entry(int pic_size) {
823 assert(_is_initialized, "StubRoutines not initialized yet");
824 assert(1 <= pic_size && pic_size <= PIC::max_nof_entries, "pic size out of range")
825 return _PIC_stub_entries[pic_size];
829 char* StubRoutines::allocate_entry(int size) {
830 assert(_is_initialized, "StubRoutines not initialized yet");
831 assert(0 <= size && size <= max_fast_allocate_size, "size out of range")
832 return _allocate_entries[size];
836 // Initialization
838 bool StubRoutines::_is_initialized = false;
839 char StubRoutines::_code[StubRoutines::_code_size];
841 char* StubRoutines::generate(MacroAssembler* masm, char* title, char* gen(MacroAssembler*)) {
842 char* old_pc = masm->pc();
843 char* entry_point = gen(masm);
844 char* new_pc = masm->pc();
845 if (!Disclaimer::is_product() && PrintStubRoutines) {
846 std->print("Stub routine: %s", title);
847 std->print(" (%d bytes), entry point = 0x%x\n", new_pc - old_pc, entry_point);
848 masm->code()->decode();
849 std->cr();
851 return entry_point;
855 char* StubRoutines::generate(MacroAssembler* masm, char* title, char* gen(MacroAssembler*, int argument), int argument) {
856 char* old_pc = masm->pc();
857 char* entry_point = gen(masm, argument);
858 char* new_pc = masm->pc();
859 if (!Disclaimer::is_product() && PrintStubRoutines) {
860 std->print("Stub routine: %s %d", title, argument);
861 std->print(" (%d bytes), entry point = 0x%x\n", new_pc - old_pc, entry_point);
862 masm->code()->decode();
863 std->cr();
865 return entry_point;
869 void StubRoutines::init() {
870 if (_is_initialized) return;
872 ResourceMark rm;
873 CodeBuffer* code = new CodeBuffer(_code, _code_size);
874 MacroAssembler* masm = new MacroAssembler(code);
876 // add generators here
877 _ic_normal_lookup_entry = generate(masm, "ic_normal_lookup", generate_ic_normal_lookup );
878 _ic_super_lookup_entry = generate(masm, "ic_super_lookup", generate_ic_super_lookup );
879 _zombie_nmethod_entry = generate(masm, "zombie_nmethod", generate_zombie_nmethod );
880 _zombie_block_nmethod_entry = generate(masm, "zombie_block_nmethod", generate_zombie_block_nmethod );
881 _megamorphic_ic_entry = generate(masm, "megamorphic_ic", generate_megamorphic_ic );
882 _compile_block_entry = generate(masm, "compile_block", generate_compile_block );
883 _continue_NLR_entry = generate(masm, "continue_NLR", generate_continue_NLR );
884 _call_sync_DLL_entry = generate(masm, "call_sync_DLL", generate_call_sync_DLL );
885 _call_async_DLL_entry = generate(masm, "call_async_DLL", generate_call_async_DLL );
886 _lookup_sync_DLL_entry = generate(masm, "lookup_sync_DLL", generate_lookup_sync_DLL );
887 _lookup_async_DLL_entry = generate(masm, "lookup_async_DLL", generate_lookup_async_DLL );
888 _recompile_stub_entry = generate(masm, "recompile_stub", generate_recompile_stub );
889 _used_uncommon_trap_entry = generate(masm, "used_uncommon_trap", generate_uncommon_trap );
890 _unused_uncommon_trap_entry = generate(masm, "unused_uncommon_trap", generate_uncommon_trap );
891 _verify_context_chain_entry = generate(masm, "verify_context_chain", generate_verify_context_chain );
892 _deoptimize_block_entry = generate(masm, "deoptimize_block", generate_deoptimize_block );
893 _call_inspector_entry = generate(masm, "call_inspector", generate_call_inspector );
895 for (int pic_size = 1; pic_size <= PIC::max_nof_entries; pic_size++) {
896 _PIC_stub_entries[pic_size] = generate(masm, "PIC stub", generate_PIC_stub, pic_size);
899 for (int size = 0; size <= max_fast_allocate_size; size++) {
900 _allocate_entries[size] = generate(masm, "allocate", generate_allocate, size);
903 masm->finalize();
904 _is_initialized = true;
905 if (!Disclaimer::is_product() && PrintStubRoutines) {
906 std->print("%d bytes generated for stub routines\n", masm->offset());
907 exit(0);
912 void stubRoutines_init() {
913 StubRoutines::init();