1 /* src/vm/jit/i386/asmpart.S - Java-C interface functions for i386
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 $Id: asmpart.S 8274 2007-08-08 15:58:17Z twisti $
34 #include "vm/jit/i386/arch.h"
35 #include "vm/jit/i386/md-abi.h"
37 #include "vm/jit/abi-asm.h"
38 #include "vm/jit/methodheader.h"
44 /* export functions ***********************************************************/
48 .globl asm_vm_call_method
49 .globl asm_vm_call_method_int
50 .globl asm_vm_call_method_long
51 .globl asm_vm_call_method_float
52 .globl asm_vm_call_method_double
53 .globl asm_vm_call_method_exception_handler
54 .globl asm_vm_call_method_end
56 .globl asm_call_jit_compiler
57 .globl asm_handle_nat_exception
58 .globl asm_handle_exception
60 .globl asm_abstractmethoderror
62 .globl asm_patcher_wrapper
64 #if defined(ENABLE_REPLACEMENT)
65 .globl asm_replacement_out
66 .globl asm_replacement_in
69 .globl asm_builtin_f2i
70 .globl asm_builtin_f2l
71 .globl asm_builtin_d2i
72 .globl asm_builtin_d2l
74 .globl asm_compare_and_swap
75 .globl asm_memory_barrier
77 .globl asm_get_cycle_count
80 /* asm_md_init *****************************************************************
82 Initialize machine dependent stuff.
84 See: http://www.srware.com/linux_numerics.txt
86 This puts the X86 FPU in 64-bit precision mode. The default under
87 Linux is to use 80-bit mode, which produces subtle differences from
88 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
89 64-bit mode, 299 in 80-bit mode.
91 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
93 *******************************************************************************/
96 sub $4,sp /* allocate space for the FPU state */
97 fnstcw (sp) /* get the FPU state */
99 and $0xfcff,%ax /* remove the extended mode flag */
100 or $0x0200,%ax /* put the double mode flag */
101 mov %eax,(sp) /* store new FPU state */
102 fldcw (sp) /* setup new FPU state */
107 /********************* function asm_calljavafunction ***************************
109 * This function calls a Java-method (which possibly needs compilation) *
110 * with up to 4 address parameters. *
112 * This functions calls the JIT-compiler which eventually translates the *
113 * method into machine code. *
116 * javaobject_header *asm_vm_call_method(methodinfo *m, *
117 * u4 count, u4 size, void *callblock); *
119 *******************************************************************************/
123 .long 0 /* catch type all */
124 .long 0 /* handler pc */
126 .long 0 /* start pc */
127 .long 1 /* extable size */
128 .long 0 /* line number table start */
129 .long 0 /* line number table size */
130 .long 0 /* fltsave */
131 .long 0 /* intsave */
134 .long 0 /* frame size */
135 .long 0 /* codeinfo pointer */
138 asm_vm_call_method_int:
139 asm_vm_call_method_long:
140 asm_vm_call_method_float:
141 asm_vm_call_method_double:
143 mov sp,bp /* save stackptr */
144 sub $(4*4),sp /* create stackframe */
145 and $0xfffffff0,sp /* align stack to 16-byte */
147 mov t0,0*4(sp) /* save registers */
151 mov sp,s1 /* save stack pointer */
153 mov 3*4(bp),t0 /* address of data structure */
154 mov 4*4(bp),itmp1 /* number of stack arguments */
157 je L_asm_vm_call_method_stack_copy_done
160 add $1,itmp2 /* keep stack 16-byte aligned */
161 and $0xfffffffe,itmp2
162 shl $3,itmp2 /* calculate stack size */
163 sub itmp2,sp /* create stack frame */
164 mov sp,itmp2 /* temporary stack pointer */
166 L_asm_vm_call_method_stack_copy_loop:
167 mov 0(t0),itmp3 /* load argument */
168 mov itmp3,0(itmp2) /* store argument on stack */
172 sub $1,itmp1 /* subtract 1 argument */
173 add $8,t0 /* set address of next argument */
174 add $8,itmp2 /* increase SP */
177 jg L_asm_vm_call_method_stack_copy_loop
179 L_asm_vm_call_method_stack_copy_done:
180 lea (2*4-256)(bp),mptr /* We subtract 256 to force the next */
181 /* move instruction to have a 32-bit */
184 mov (0*4+256)(mptr),itmp3 /* method call as in Java */
185 call *itmp3 /* call JIT compiler */
187 L_asm_vm_call_method_return:
188 mov s1,sp /* restore stackpointer */
190 mov 0*4(sp),t0 /* restore registers */
197 asm_vm_call_method_exception_handler:
198 push xptr /* pass exception pointer */
199 call builtin_throw_exception
201 asm_vm_call_method_end:
202 jmp L_asm_vm_call_method_return
205 /* asm_call_jit_compiler *******************************************************
207 Invokes the compiler for untranslated JavaVM methods.
209 Register R0 contains a pointer to the method info structure (prepared
210 by createcompilerstub). Using the return address in R26 and the
211 offset in the LDA instruction or using the value in methodptr R28 the
212 patching address for storing the method address can be computed:
214 Method address was either loaded using
216 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
217 i386_call_reg(REG_ITMP2)
221 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
222 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
223 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
224 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
225 i386_call_reg(REG_ITMP1)
227 In the static case the method pointer can be computed using the
228 return address and the lda function following the jmp instruction.
230 *******************************************************************************/
232 asm_call_jit_compiler:
233 L_asm_call_jit_compiler: /* required for PIC code */
234 sub $(4*4),sp /* keep stack 16-byte aligned */
236 mov itmp1,0*4(sp) /* pass methodinfo pointer */
237 mov mptr,1*4(sp) /* pass method pointer */
238 mov sp,itmp2 /* pass java sp */
241 mov 4*4(sp),itmp3 /* pass java ra */
245 add $(4*4),sp /* remove stack frame */
247 test v0,v0 /* check for exception */
248 je L_asm_call_jit_compiler_exception
250 jmp *v0 /* ...and now call the new method */
252 L_asm_call_jit_compiler_exception:
253 call exceptions_get_and_clear_exception
255 pop xpc /* get return address */
256 sub $2,xpc /* faulting address is ra - 2 */
257 jmp L_asm_handle_exception
260 /* asm_handle_exception ********************************************************
262 * This function handles an exception. It does not use the usual calling *
263 * conventions. The exception pointer is passed in REG_ITMP1 and the *
264 * pc from the exception raising position is passed in REG_ITMP2. It searches *
265 * the local exception table for a handler. If no one is found, it unwinds *
266 * stacks and continues searching the callers. *
268 *******************************************************************************/
270 asm_handle_nat_exception:
271 add $4,sp /* clear return address of native stub*/
273 asm_handle_exception:
274 L_asm_handle_exception: /* required for PIC code */
275 sub $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned */
277 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
278 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
280 mov $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
281 mov $1,t0 /* set maybe-leaf flag */
283 L_asm_handle_exception_stack_loop:
284 sub $(12*4),sp /* keep stack 16-byte aligned */
285 mov xptr,4*4(sp) /* save exception pointer */
286 mov xpc,5*4(sp) /* save exception pc */
287 add sp,itmp3 /* calculate Java sp into a3... */
289 mov itmp3,7*4(sp) /* ...and save it */
290 mov t0,8*4(sp) /* save maybe-leaf flag */
292 mov xpc,0*4(sp) /* pass exception pc */
293 call codegen_get_pv_from_pc
294 mov v0,6*4(sp) /* save data segment pointer */
296 mov 4*4(sp),itmp3 /* pass exception pointer */
298 mov 5*4(sp),itmp3 /* pass exception pc */
300 mov v0,2*4(sp) /* pass data segment pointer */
301 mov 7*4(sp),itmp3 /* pass Java stack pointer */
303 call exceptions_handle_exception
306 jz L_asm_handle_exception_not_catched
308 mov v0,xpc /* move handlerpc into xpc */
309 mov 4*4(sp),xptr /* restore exception pointer */
310 mov 8*4(sp),t0 /* get maybe-leaf flag */
311 add $(12*4),sp /* free stackframe */
313 test t0,t0 /* test for maybe-leaf flag */
314 jz L_asm_handle_exception_no_leaf
316 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
317 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
319 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
321 L_asm_handle_exception_no_leaf:
322 jmp *xpc /* jump to exception handler */
324 L_asm_handle_exception_not_catched:
325 mov 4*4(sp),xptr /* restore exception pointer */
326 mov 6*4(sp),itmp3 /* restore data segment pointer */
327 mov 8*4(sp),t0 /* get maybe-leaf flag */
328 add $(12*4),sp /* free stackframe */
331 jz L_asm_handle_exception_no_leaf_stack
333 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
334 xor t0,t0 /* clear the maybe-leaf flag */
336 L_asm_handle_exception_no_leaf_stack:
337 mov FrameSize(itmp3),itmp2 /* get frame size */
338 add sp,itmp2 /* pointer to save area */
340 push xptr /* we are out of registers */
342 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
357 shl $2,itmp1 /* multiply by 4 bytes */
362 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
387 pop xptr /* restore exception pointer */
388 mov FrameSize(itmp3),itmp2 /* get frame size */
389 add itmp2,sp /* unwind stack */
391 pop xpc /* the new xpc is return address */
392 sub $2,xpc /* subtract 2-bytes for call */
394 xor itmp3,itmp3 /* prepare a3 for handle_exception */
396 jmp L_asm_handle_exception_stack_loop
399 /* asm_abstractmethoderror *****************************************************
401 Creates and throws an AbstractMethodError.
403 *******************************************************************************/
405 asm_abstractmethoderror:
406 sub $(3*4),sp /* keep stack 16-byte aligned */
407 mov sp,itmp1 /* pass java sp */
410 mov 3*4(sp),itmp2 /* pass exception address */
413 call exceptions_asm_new_abstractmethoderror
414 /* exception pointer is return value */
415 add $(3*4),sp /* remove stack frame */
417 pop xpc /* get exception address */
418 sub $2,xpc /* exception address is ra - 2 */
419 jmp L_asm_handle_exception
422 /* asm_patcher_wrapper *********************************************************
429 16 pointer to virtual java_objectheader
430 12 last byte of machine code (xmcode)
431 8 machine code (which is patched back later)
432 4 unresolved field reference
433 0 patcher function pointer to call
435 *******************************************************************************/
438 sub $((1+4+4)*4),sp /* keep stack 16-byte aligned */
440 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
441 mov itmp2,(1+4)*4(sp)
443 mov sp,itmp1 /* pass SP of patcher stub */
444 add $((1+4+4)*4),itmp1
446 movl $0,1*4(sp) /* pass PV (if NULL, use findmethod) */
447 movl $0,2*4(sp) /* pass RA (it's on the stack) */
449 mov v0,itmp3 /* save return value */
451 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
452 mov (1+4)*4(sp),itmp2
454 test itmp3,itmp3 /* exception thrown? */
455 jne L_asm_patcher_wrapper_exception
457 mov (5+1+4+4)*4(sp),itmp3 /* restore itmp3 */
458 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
460 ret /* jump to new patched code */
462 L_asm_patcher_wrapper_exception:
463 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
464 mov itmp3,xptr /* get exception */
465 pop xpc /* get and remove return address */
466 jmp L_asm_handle_exception
468 #if defined(ENABLE_REPLACEMENT)
470 /* asm_replacement_out *********************************************************
472 This code is jumped to from the replacement-out stubs that are executed
473 when a thread reaches an activated replacement point.
475 The purpose of asm_replacement_out is to read out the parts of the
476 execution state that cannot be accessed from C code, store this state,
477 and then call the C function replace_me.
480 4 start of stack inside method to replace
481 0 rplpoint * info on the replacement point that was reached
483 *******************************************************************************/
485 /* some room to accomodate changes of the stack frame size during replacement */
486 /* XXX we should find a cleaner solution here */
487 #define REPLACEMENT_ROOM 512
490 /* create stack frame */
491 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
493 /* save registers in execution state */
494 mov %eax,(EAX*4+offes_intregs)(sp)
495 mov %ebx,(EBX*4+offes_intregs)(sp)
496 mov %ecx,(ECX*4+offes_intregs)(sp)
497 mov %edx,(EDX*4+offes_intregs)(sp)
498 mov %esi,(ESI*4+offes_intregs)(sp)
499 mov %edi,(EDI*4+offes_intregs)(sp)
500 mov %ebp,(EBP*4+offes_intregs)(sp)
501 movl $0 ,(ESP*4+offes_intregs)(sp) /* not used */
503 /* calculate sp of method */
505 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
506 mov itmp1,(offes_sp)(sp)
508 /* pv must be looked up via AVL tree */
509 movl $0,(offes_pv)(sp)
511 /* call replace_me */
512 mov -4(itmp1),itmp1 /* rplpoint * */
513 push sp /* arg1: execution state */
514 push itmp1 /* arg0: replacement point */
515 call replace_me /* call C function replace_me */
518 /* asm_replacement_in **********************************************************
520 This code writes the given execution state and jumps to the replacement
523 This function never returns!
526 void asm_replacement_in(executionstate *es, replace_safestack_t *st);
528 *******************************************************************************/
532 mov 8(sp),%esi /* replace_safestack_t *st */
533 mov 4(sp),%ebp /* executionstate *es == safe stack */
535 /* switch to the safe stack and build a stack frame */
539 /* call replace_build_execution_state(st) */
541 call replace_build_execution_state
544 mov (offes_sp)(%ebp),sp
546 /* push address of new code */
547 push (offes_pc)(%ebp)
549 /* allocate an executionstate_t on the stack */
550 sub $(sizeexecutionstate),sp
552 /* call replace_free_safestack(st,& of allocated executionstate_t) */
555 call replace_free_safestack
558 /* copy registers from execution state */
559 mov (EAX*4+offes_intregs)(sp),%eax
560 mov (EBX*4+offes_intregs)(sp),%ebx
561 mov (ECX*4+offes_intregs)(sp),%ecx
562 mov (EDX*4+offes_intregs)(sp),%edx
563 mov (ESI*4+offes_intregs)(sp),%esi
564 mov (EDI*4+offes_intregs)(sp),%edi
565 mov (EBP*4+offes_intregs)(sp),%ebp
567 /* pop the execution state off the stack */
568 add $(sizeexecutionstate),sp
570 /* jump to new code, hold your thumbs! ;) */
573 #endif /* defined(ENABLE_REPLACEMENT) */
576 /************************ function asm_builtin_x2x *****************************
578 * Wrapper functions for corner cases *
580 *******************************************************************************/
611 /* asm_compare_and_swap ********************************************************
613 Does an atomic compare and swap. Required for the lock
616 Atomically do the following: Check if the location still contains
617 `oldval`. If so, replace it by `newval` and return `oldval`.
622 long compare_and_swap(volatile long *p, long oldval, long newval);
624 *******************************************************************************/
626 asm_compare_and_swap:
627 mov 1*4(sp),%ecx /* load p into a register */
628 mov 2*4(sp),%eax /* load oldval into return register */
629 mov 3*4(sp),%edx /* load newval into a register */
630 lock; cmpxchgl %edx,0(%ecx)
634 /* asm_memory_barrier **********************************************************
636 A memory barrier for the Java Memory Model.
638 *******************************************************************************/
645 /* asm_get_cycle_count *********************************************************
647 Get the current time-stamp counter from the CPU.
649 *******************************************************************************/
656 /* disable exec-stacks ********************************************************/
658 #if defined(__linux__) && defined(__ELF__)
659 .section .note.GNU-stack,"",%progbits
664 * These are local overrides for various environment variables in Emacs.
665 * Please do not remove this and leave it at the end of the file, where
666 * Emacs will automagically detect them.
667 * ---------------------------------------------------------------------
670 * indent-tabs-mode: t
674 * vim:noexpandtab:sw=4:ts=4: