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
32 #include "vm/jit/i386/arch.h"
33 #include "vm/jit/i386/md-abi.h"
35 #include "vm/jit/abi-asm.h"
36 #include "vm/jit/methodheader.h"
42 /* export functions ***********************************************************/
46 .globl asm_vm_call_method
47 .globl asm_vm_call_method_int
48 .globl asm_vm_call_method_long
49 .globl asm_vm_call_method_float
50 .globl asm_vm_call_method_double
51 .globl asm_vm_call_method_exception_handler
52 .globl asm_vm_call_method_end
54 .globl asm_call_jit_compiler
55 .globl asm_handle_nat_exception
56 .globl asm_handle_exception
58 .globl asm_abstractmethoderror
60 #if defined(ENABLE_REPLACEMENT)
61 .globl asm_replacement_out
62 .globl asm_replacement_in
65 .globl asm_builtin_f2i
66 .globl asm_builtin_f2l
67 .globl asm_builtin_d2i
68 .globl asm_builtin_d2l
70 .globl asm_compare_and_swap
71 .globl asm_memory_barrier
73 .globl asm_get_cycle_count
76 /* asm_md_init *****************************************************************
78 Initialize machine dependent stuff.
80 See: http://www.srware.com/linux_numerics.txt
82 This puts the X86 FPU in 64-bit precision mode. The default under
83 Linux is to use 80-bit mode, which produces subtle differences from
84 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
85 64-bit mode, 299 in 80-bit mode.
87 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
89 *******************************************************************************/
92 sub $4,sp /* allocate space for the FPU state */
93 fnstcw (sp) /* get the FPU state */
95 and $0xfcff,%ax /* remove the extended mode flag */
96 or $0x0200,%ax /* put the double mode flag */
97 mov %eax,(sp) /* store new FPU state */
98 fldcw (sp) /* setup new FPU state */
103 /********************* function asm_calljavafunction ***************************
105 * This function calls a Java-method (which possibly needs compilation) *
106 * with up to 4 address parameters. *
108 * This functions calls the JIT-compiler which eventually translates the *
109 * method into machine code. *
112 * javaobject_header *asm_vm_call_method(methodinfo *m, *
113 * u4 count, u4 size, void *callblock); *
115 *******************************************************************************/
119 .long 0 /* catch type all */
120 .long 0 /* handler pc */
122 .long 0 /* start pc */
123 .long 1 /* extable size */
124 .long 0 /* line number table start */
125 .long 0 /* line number table size */
126 .long 0 /* fltsave */
127 .long 0 /* intsave */
130 .long 0 /* frame size */
131 .long 0 /* codeinfo pointer */
134 asm_vm_call_method_int:
135 asm_vm_call_method_long:
136 asm_vm_call_method_float:
137 asm_vm_call_method_double:
139 mov sp,bp /* save stackptr */
140 sub $(4*4),sp /* create stackframe */
141 and $0xfffffff0,sp /* align stack to 16-byte */
143 mov t0,0*4(sp) /* save registers */
147 mov sp,s1 /* save stack pointer */
149 mov 3*4(bp),t0 /* address of data structure */
150 mov 4*4(bp),itmp1 /* number of stack arguments */
153 je L_asm_vm_call_method_stack_copy_done
156 add $1,itmp2 /* keep stack 16-byte aligned */
157 and $0xfffffffe,itmp2
158 shl $3,itmp2 /* calculate stack size */
159 sub itmp2,sp /* create stack frame */
160 mov sp,itmp2 /* temporary stack pointer */
162 L_asm_vm_call_method_stack_copy_loop:
163 mov 0(t0),itmp3 /* load argument */
164 mov itmp3,0(itmp2) /* store argument on stack */
168 sub $1,itmp1 /* subtract 1 argument */
169 add $8,t0 /* set address of next argument */
170 add $8,itmp2 /* increase SP */
173 jg L_asm_vm_call_method_stack_copy_loop
175 L_asm_vm_call_method_stack_copy_done:
176 lea (2*4-256)(bp),mptr /* We subtract 256 to force the next */
177 /* move instruction to have a 32-bit */
180 mov (0*4+256)(mptr),itmp3 /* method call as in Java */
181 call *itmp3 /* call JIT compiler */
183 L_asm_vm_call_method_return:
184 mov s1,sp /* restore stackpointer */
186 mov 0*4(sp),t0 /* restore registers */
193 asm_vm_call_method_exception_handler:
194 push xptr /* pass exception pointer */
195 call builtin_throw_exception
197 asm_vm_call_method_end:
198 jmp L_asm_vm_call_method_return
201 /* asm_call_jit_compiler *******************************************************
203 Invokes the compiler for untranslated JavaVM methods.
205 Register R0 contains a pointer to the method info structure (prepared
206 by createcompilerstub). Using the return address in R26 and the
207 offset in the LDA instruction or using the value in methodptr R28 the
208 patching address for storing the method address can be computed:
210 Method address was either loaded using
212 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
213 i386_call_reg(REG_ITMP2)
217 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
218 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
219 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
220 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
221 i386_call_reg(REG_ITMP1)
223 In the static case the method pointer can be computed using the
224 return address and the lda function following the jmp instruction.
226 *******************************************************************************/
228 asm_call_jit_compiler:
229 L_asm_call_jit_compiler: /* required for PIC code */
230 sub $(4*4),sp /* keep stack 16-byte aligned */
232 mov itmp1,0*4(sp) /* pass methodinfo pointer */
233 mov mptr,1*4(sp) /* pass method pointer */
234 mov sp,itmp2 /* pass java sp */
237 mov 4*4(sp),itmp3 /* pass java ra */
241 add $(4*4),sp /* remove stack frame */
243 test v0,v0 /* check for exception */
244 je L_asm_call_jit_compiler_exception
246 jmp *v0 /* ...and now call the new method */
248 L_asm_call_jit_compiler_exception:
249 call exceptions_get_and_clear_exception
251 pop xpc /* get return address */
252 sub $2,xpc /* faulting address is ra - 2 */
253 jmp L_asm_handle_exception
256 /* asm_handle_exception ********************************************************
258 * This function handles an exception. It does not use the usual calling *
259 * conventions. The exception pointer is passed in REG_ITMP1 and the *
260 * pc from the exception raising position is passed in REG_ITMP2. It searches *
261 * the local exception table for a handler. If no one is found, it unwinds *
262 * stacks and continues searching the callers. *
264 *******************************************************************************/
266 asm_handle_nat_exception:
267 add $4,sp /* clear return address of native stub*/
269 asm_handle_exception:
270 L_asm_handle_exception: /* required for PIC code */
271 sub $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned */
273 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
274 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
276 mov $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
277 mov $1,t0 /* set maybe-leaf flag */
279 L_asm_handle_exception_stack_loop:
280 sub $(12*4),sp /* keep stack 16-byte aligned */
281 mov xptr,4*4(sp) /* save exception pointer */
282 mov xpc,5*4(sp) /* save exception pc */
283 add sp,itmp3 /* calculate Java sp into a3... */
285 mov itmp3,7*4(sp) /* ...and save it */
286 mov t0,8*4(sp) /* save maybe-leaf flag */
288 mov xpc,0*4(sp) /* pass exception pc */
289 call codegen_get_pv_from_pc
290 mov v0,6*4(sp) /* save data segment pointer */
292 mov 4*4(sp),itmp3 /* pass exception pointer */
294 mov 5*4(sp),itmp3 /* pass exception pc */
296 mov v0,2*4(sp) /* pass data segment pointer */
297 mov 7*4(sp),itmp3 /* pass Java stack pointer */
299 call exceptions_handle_exception
302 jz L_asm_handle_exception_not_catched
304 mov v0,xpc /* move handlerpc into xpc */
305 mov 4*4(sp),xptr /* restore exception pointer */
306 mov 8*4(sp),t0 /* get maybe-leaf flag */
307 add $(12*4),sp /* free stackframe */
309 test t0,t0 /* test for maybe-leaf flag */
310 jz L_asm_handle_exception_no_leaf
312 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
313 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
315 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
317 L_asm_handle_exception_no_leaf:
318 jmp *xpc /* jump to exception handler */
320 L_asm_handle_exception_not_catched:
321 mov 4*4(sp),xptr /* restore exception pointer */
322 mov 6*4(sp),itmp3 /* restore data segment pointer */
323 mov 8*4(sp),t0 /* get maybe-leaf flag */
324 add $(12*4),sp /* free stackframe */
327 jz L_asm_handle_exception_no_leaf_stack
329 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
330 xor t0,t0 /* clear the maybe-leaf flag */
332 L_asm_handle_exception_no_leaf_stack:
333 mov FrameSize(itmp3),itmp2 /* get frame size */
334 add sp,itmp2 /* pointer to save area */
336 push xptr /* we are out of registers */
338 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
353 shl $2,itmp1 /* multiply by 4 bytes */
358 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
383 pop xptr /* restore exception pointer */
384 mov FrameSize(itmp3),itmp2 /* get frame size */
385 add itmp2,sp /* unwind stack */
387 pop xpc /* the new xpc is return address */
388 sub $2,xpc /* subtract 2-bytes for call */
390 xor itmp3,itmp3 /* prepare a3 for handle_exception */
392 jmp L_asm_handle_exception_stack_loop
395 /* asm_abstractmethoderror *****************************************************
397 Creates and throws an AbstractMethodError.
399 *******************************************************************************/
401 asm_abstractmethoderror:
402 sub $(3*4),sp /* keep stack 16-byte aligned */
403 mov sp,itmp1 /* pass java sp */
406 mov 3*4(sp),itmp2 /* pass exception address */
409 call exceptions_asm_new_abstractmethoderror
410 /* exception pointer is return value */
411 add $(3*4),sp /* remove stack frame */
413 pop xpc /* get exception address */
414 sub $2,xpc /* exception address is ra - 2 */
415 jmp L_asm_handle_exception
418 #if defined(ENABLE_REPLACEMENT)
420 /* asm_replacement_out *********************************************************
422 This code is jumped to from the replacement-out stubs that are executed
423 when a thread reaches an activated replacement point.
425 The purpose of asm_replacement_out is to read out the parts of the
426 execution state that cannot be accessed from C code, store this state,
427 and then call the C function replace_me.
430 4 start of stack inside method to replace
431 0 rplpoint * info on the replacement point that was reached
433 *******************************************************************************/
435 /* some room to accomodate changes of the stack frame size during replacement */
436 /* XXX we should find a cleaner solution here */
437 #define REPLACEMENT_ROOM 512
440 /* create stack frame */
441 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
443 /* save registers in execution state */
444 mov %eax,(EAX*4+offes_intregs)(sp)
445 mov %ebx,(EBX*4+offes_intregs)(sp)
446 mov %ecx,(ECX*4+offes_intregs)(sp)
447 mov %edx,(EDX*4+offes_intregs)(sp)
448 mov %esi,(ESI*4+offes_intregs)(sp)
449 mov %edi,(EDI*4+offes_intregs)(sp)
450 mov %ebp,(EBP*4+offes_intregs)(sp)
451 movl $0 ,(ESP*4+offes_intregs)(sp) /* not used */
453 /* calculate sp of method */
455 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
456 mov itmp1,(offes_sp)(sp)
458 /* pv must be looked up via AVL tree */
459 movl $0,(offes_pv)(sp)
461 /* call replace_me */
462 mov -4(itmp1),itmp1 /* rplpoint * */
463 push sp /* arg1: execution state */
464 push itmp1 /* arg0: replacement point */
465 call replace_me /* call C function replace_me */
468 /* asm_replacement_in **********************************************************
470 This code writes the given execution state and jumps to the replacement
473 This function never returns!
476 void asm_replacement_in(executionstate *es, replace_safestack_t *st);
478 *******************************************************************************/
482 mov 8(sp),%esi /* replace_safestack_t *st */
483 mov 4(sp),%ebp /* executionstate *es == safe stack */
485 /* switch to the safe stack and build a stack frame */
489 /* call replace_build_execution_state(st) */
491 call replace_build_execution_state
494 mov (offes_sp)(%ebp),sp
496 /* push address of new code */
497 push (offes_pc)(%ebp)
499 /* allocate an executionstate_t on the stack */
500 sub $(sizeexecutionstate),sp
502 /* call replace_free_safestack(st,& of allocated executionstate_t) */
505 call replace_free_safestack
508 /* copy registers from execution state */
509 mov (EAX*4+offes_intregs)(sp),%eax
510 mov (EBX*4+offes_intregs)(sp),%ebx
511 mov (ECX*4+offes_intregs)(sp),%ecx
512 mov (EDX*4+offes_intregs)(sp),%edx
513 mov (ESI*4+offes_intregs)(sp),%esi
514 mov (EDI*4+offes_intregs)(sp),%edi
515 mov (EBP*4+offes_intregs)(sp),%ebp
517 /* pop the execution state off the stack */
518 add $(sizeexecutionstate),sp
520 /* jump to new code, hold your thumbs! ;) */
523 #endif /* defined(ENABLE_REPLACEMENT) */
526 /************************ function asm_builtin_x2x *****************************
528 * Wrapper functions for corner cases *
530 *******************************************************************************/
561 /* asm_compare_and_swap ********************************************************
563 Does an atomic compare and swap. Required for the lock
566 Atomically do the following: Check if the location still contains
567 `oldval`. If so, replace it by `newval` and return `oldval`.
572 long compare_and_swap(volatile long *p, long oldval, long newval);
574 *******************************************************************************/
576 asm_compare_and_swap:
577 mov 1*4(sp),%ecx /* load p into a register */
578 mov 2*4(sp),%eax /* load oldval into return register */
579 mov 3*4(sp),%edx /* load newval into a register */
580 lock; cmpxchgl %edx,0(%ecx)
584 /* asm_memory_barrier **********************************************************
586 A memory barrier for the Java Memory Model.
588 *******************************************************************************/
595 /* asm_get_cycle_count *********************************************************
597 Get the current time-stamp counter from the CPU.
599 *******************************************************************************/
606 /* disable exec-stacks ********************************************************/
608 #if defined(__linux__) && defined(__ELF__)
609 .section .note.GNU-stack,"",%progbits
614 * These are local overrides for various environment variables in Emacs.
615 * Please do not remove this and leave it at the end of the file, where
616 * Emacs will automagically detect them.
617 * ---------------------------------------------------------------------
620 * indent-tabs-mode: t
624 * vim:noexpandtab:sw=4:ts=4: