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 7355 2007-02-14 10:57:32Z twisti $
34 #include "vm/jit/i386/arch.h"
35 #include "vm/jit/i386/md-abi.h"
36 #include "vm/jit/i386/offsets.h"
38 #include "vm/jit/abi-asm.h"
39 #include "vm/jit/methodheader.h"
45 /* export functions ***********************************************************/
49 .globl asm_vm_call_method
50 .globl asm_vm_call_method_int
51 .globl asm_vm_call_method_long
52 .globl asm_vm_call_method_float
53 .globl asm_vm_call_method_double
54 .globl asm_vm_call_method_exception_handler
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_criticalsections
78 .globl asm_getclassvalues_atomic
80 .globl asm_get_cycle_count
83 /* asm_md_init *****************************************************************
85 Initialize machine dependent stuff.
87 See: http://www.srware.com/linux_numerics.txt
89 This puts the X86 FPU in 64-bit precision mode. The default under
90 Linux is to use 80-bit mode, which produces subtle differences from
91 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
92 64-bit mode, 299 in 80-bit mode.
94 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
96 *******************************************************************************/
99 sub $4,sp /* allocate space for the FPU state */
100 fnstcw (sp) /* get the FPU state */
102 and $0xfcff,%ax /* remove the extended mode flag */
103 or $0x0200,%ax /* put the double mode flag */
104 mov %eax,(sp) /* store new FPU state */
105 fldcw (sp) /* setup new FPU state */
110 /********************* function asm_calljavafunction ***************************
112 * This function calls a Java-method (which possibly needs compilation) *
113 * with up to 4 address parameters. *
115 * This functions calls the JIT-compiler which eventually translates the *
116 * method into machine code. *
119 * javaobject_header *asm_vm_call_method(methodinfo *m, *
120 * u4 count, u4 size, void *callblock); *
122 *******************************************************************************/
126 .long 0 /* catch type all */
127 .long 0 /* handler pc */
129 .long 0 /* start pc */
130 .long 1 /* extable size */
131 .long 0 /* line number table start */
132 .long 0 /* line number table size */
133 .long 0 /* fltsave */
134 .long 0 /* intsave */
137 .long 0 /* frame size */
138 .long 0 /* codeinfo pointer */
141 asm_vm_call_method_int:
142 asm_vm_call_method_long:
143 asm_vm_call_method_float:
144 asm_vm_call_method_double:
146 mov sp,bp /* save stackptr */
147 sub $(4*4),sp /* create stackframe */
148 and $0xfffffff0,sp /* align stack to 16-byte */
150 mov t0,0*4(sp) /* save registers */
154 mov 4*4(bp),itmp1 /* pointer to arg block (4(push)+4(return)+4+4)*/
155 mov 3*4(bp),itmp2 /* arg count (4(push)+4(return)+4 */
157 mov sp,s1 /* save the stackpointer */
159 test itmp2,itmp2 /* maybe we have no args */
160 jle L_asm_vm_call_method_copy_done
162 mov itmp2,itmp3 /* calculate stack size */
163 mov itmp1,%edi /* save pointer to arg block */
165 calljava_calcstacksize:
166 mov offvmargtype(itmp1),t0
167 test $1,t0 /* two word type? */
168 jz calljava_onewordtype
170 sub $4,sp /* add 1 slot to stackframe size */
172 calljava_onewordtype:
173 sub $4,sp /* add 1 slot to stackframe size */
175 test itmp3,itmp3 /* any args left? */
178 add $sizevmarg,itmp1 /* goto next argument block */
179 jmp calljava_calcstacksize
182 mov %edi,itmp1 /* restore pointer to arg block */
183 and $0xfffffff0,sp /* align stack to 16-byte */
184 mov sp,itmp3 /* initialize pointer for copying */
187 mov offvmargdata(itmp1),t0 /* get 4-bytes of argument */
188 mov t0,(itmp3) /* and store them on the stack */
189 add $4,itmp3 /* increase sp to next argument */
191 mov offvmargtype(itmp1),t0 /* get the argument type */
192 test $1,t0 /* two word type? */
195 mov offvmargdata+4(itmp1),t0 /* get upper 4-bytes of 2 word type */
197 add $4,itmp3 /* increase sp to next argument */
200 sub $1,itmp2 /* are there any args left? */
202 jle L_asm_vm_call_method_copy_done
204 add $sizevmarg,itmp1 /* goto next argument block */
205 jmp calljava_copyloop
207 L_asm_vm_call_method_copy_done:
208 mov 2*4(bp),itmp1 /* move function pointer to itmp1 */
210 lea L_asm_call_jit_compiler,mptr
212 lea (3*4-256)(s1),mptr /* We subtract 256 to force the next */
213 /* move instruction to have a 32-bit */
216 mov (0*4+256)(mptr),itmp3 /* method call as in Java */
217 call *itmp3 /* call JIT compiler */
219 L_asm_vm_call_method_return:
220 mov s1,sp /* restore stackpointer */
222 mov 0*4(sp),t0 /* restore registers */
229 asm_vm_call_method_exception_handler:
230 push xptr /* pass exception pointer */
231 call builtin_throw_exception
233 jmp L_asm_vm_call_method_return
236 /* asm_call_jit_compiler *******************************************************
238 Invokes the compiler for untranslated JavaVM methods.
240 Register R0 contains a pointer to the method info structure (prepared
241 by createcompilerstub). Using the return address in R26 and the
242 offset in the LDA instruction or using the value in methodptr R28 the
243 patching address for storing the method address can be computed:
245 Method address was either loaded using
247 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
248 i386_call_reg(REG_ITMP2)
252 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
253 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
254 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
255 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
256 i386_call_reg(REG_ITMP1)
258 In the static case the method pointer can be computed using the
259 return address and the lda function following the jmp instruction.
261 *******************************************************************************/
263 asm_call_jit_compiler:
264 L_asm_call_jit_compiler: /* required for PIC code */
265 sub $(4*4),sp /* keep stack 16-byte aligned */
267 mov itmp1,0*4(sp) /* pass methodinfo pointer */
268 mov mptr,1*4(sp) /* pass method pointer */
269 mov sp,itmp2 /* pass java sp */
272 mov 4*4(sp),itmp3 /* pass java ra */
276 add $(4*4),sp /* remove stack frame */
278 test v0,v0 /* check for exception */
279 je L_asm_call_jit_compiler_exception
281 jmp *v0 /* ...and now call the new method */
283 L_asm_call_jit_compiler_exception:
284 call exceptions_get_and_clear_exception
286 pop xpc /* get return address */
287 sub $2,xpc /* faulting address is ra - 2 */
288 jmp L_asm_handle_exception
291 /* asm_handle_exception ********************************************************
293 * This function handles an exception. It does not use the usual calling *
294 * conventions. The exception pointer is passed in REG_ITMP1 and the *
295 * pc from the exception raising position is passed in REG_ITMP2. It searches *
296 * the local exception table for a handler. If no one is found, it unwinds *
297 * stacks and continues searching the callers. *
299 *******************************************************************************/
301 asm_handle_nat_exception:
302 add $4,sp /* clear return address of native stub*/
304 asm_handle_exception:
305 L_asm_handle_exception: /* required for PIC code */
306 sub $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned */
308 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
309 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
311 mov $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
312 mov $1,t0 /* set maybe-leaf flag */
314 L_asm_handle_exception_stack_loop:
315 sub $(12*4),sp /* keep stack 16-byte aligned */
316 mov xptr,4*4(sp) /* save exception pointer */
317 mov xpc,5*4(sp) /* save exception pc */
318 add sp,itmp3 /* calculate Java sp into a3... */
320 mov itmp3,7*4(sp) /* ...and save it */
321 mov t0,8*4(sp) /* save maybe-leaf flag */
323 mov xpc,0*4(sp) /* pass exception pc */
324 call codegen_get_pv_from_pc
325 mov v0,6*4(sp) /* save data segment pointer */
327 mov 4*4(sp),itmp3 /* pass exception pointer */
329 mov 5*4(sp),itmp3 /* pass exception pc */
331 mov v0,2*4(sp) /* pass data segment pointer */
332 mov 7*4(sp),itmp3 /* pass Java stack pointer */
334 call exceptions_handle_exception
337 jz L_asm_handle_exception_not_catched
339 mov v0,xpc /* move handlerpc into xpc */
340 mov 4*4(sp),xptr /* restore exception pointer */
341 mov 8*4(sp),t0 /* get maybe-leaf flag */
342 add $(12*4),sp /* free stackframe */
344 test t0,t0 /* test for maybe-leaf flag */
345 jz L_asm_handle_exception_no_leaf
347 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
348 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
350 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
352 L_asm_handle_exception_no_leaf:
353 jmp *xpc /* jump to exception handler */
355 L_asm_handle_exception_not_catched:
356 mov 4*4(sp),xptr /* restore exception pointer */
357 mov 6*4(sp),itmp3 /* restore data segment pointer */
358 mov 8*4(sp),t0 /* get maybe-leaf flag */
359 add $(12*4),sp /* free stackframe */
362 jz L_asm_handle_exception_no_leaf_stack
364 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
365 xor t0,t0 /* clear the maybe-leaf flag */
367 L_asm_handle_exception_no_leaf_stack:
368 mov FrameSize(itmp3),itmp2 /* get frame size */
369 add sp,itmp2 /* pointer to save area */
371 push xptr /* we are out of registers */
373 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
388 shl $2,itmp1 /* multiply by 4 bytes */
393 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
418 pop xptr /* restore exception pointer */
419 mov FrameSize(itmp3),itmp2 /* get frame size */
420 add itmp2,sp /* unwind stack */
422 pop xpc /* the new xpc is return address */
423 sub $2,xpc /* subtract 2-bytes for call */
425 xor itmp3,itmp3 /* prepare a3 for handle_exception */
427 jmp L_asm_handle_exception_stack_loop
430 /* asm_abstractmethoderror *****************************************************
432 Creates and throws an AbstractMethodError.
434 *******************************************************************************/
436 asm_abstractmethoderror:
437 sub $(3*4),sp /* keep stack 16-byte aligned */
438 mov sp,itmp1 /* pass java sp */
441 mov 3*4(sp),itmp2 /* pass exception address */
444 call exceptions_asm_new_abstractmethoderror
445 /* exception pointer is return value */
446 add $(3*4),sp /* remove stack frame */
448 pop xpc /* get exception address */
449 sub $2,xpc /* exception address is ra - 2 */
450 jmp L_asm_handle_exception
453 /* asm_patcher_wrapper *********************************************************
460 16 pointer to virtual java_objectheader
461 12 last byte of machine code (xmcode)
462 8 machine code (which is patched back later)
463 4 unresolved field reference
464 0 patcher function pointer to call
466 *******************************************************************************/
469 sub $((1+4+4)*4),sp /* keep stack 16-byte aligned */
471 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
472 mov itmp2,(1+4)*4(sp)
474 mov sp,itmp1 /* pass SP of patcher stub */
475 add $((1+4+4)*4),itmp1
477 movl $0,1*4(sp) /* pass PV (if NULL, use findmethod) */
478 movl $0,2*4(sp) /* pass RA (it's on the stack) */
480 mov v0,itmp3 /* save return value */
482 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
483 mov (1+4)*4(sp),itmp2
485 test itmp3,itmp3 /* exception thrown? */
486 jne L_asm_patcher_wrapper_exception
488 mov (5+1+4+4)*4(sp),itmp3 /* restore itmp3 */
489 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
491 ret /* jump to new patched code */
493 L_asm_patcher_wrapper_exception:
494 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
495 mov itmp3,xptr /* get exception */
496 pop xpc /* get and remove return address */
497 jmp L_asm_handle_exception
499 #if defined(ENABLE_REPLACEMENT)
501 /* asm_replacement_out *********************************************************
503 This code is jumped to from the replacement-out stubs that are executed
504 when a thread reaches an activated replacement point.
506 The purpose of asm_replacement_out is to read out the parts of the
507 execution state that cannot be accessed from C code, store this state,
508 and then call the C function replace_me.
511 4 start of stack inside method to replace
512 0 rplpoint * info on the replacement point that was reached
514 *******************************************************************************/
516 /* some room to accomodate changes of the stack frame size during replacement */
517 /* XXX we should find a cleaner solution here */
518 #define REPLACEMENT_ROOM 512
521 /* create stack frame */
522 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
524 /* save registers in execution state */
525 mov %eax,(EAX*4+offes_intregs)(sp)
526 mov %ebx,(EBX*4+offes_intregs)(sp)
527 mov %ecx,(ECX*4+offes_intregs)(sp)
528 mov %edx,(EDX*4+offes_intregs)(sp)
529 mov %esi,(ESI*4+offes_intregs)(sp)
530 mov %edi,(EDI*4+offes_intregs)(sp)
531 mov %ebp,(EBP*4+offes_intregs)(sp)
532 movl $0 ,(ESP*4+offes_intregs)(sp) /* not used */
534 /* calculate sp of method */
536 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
537 mov itmp1,(offes_sp)(sp)
539 /* pv must be looked up via AVL tree */
540 movl $0,(offes_pv)(sp)
542 /* call replace_me */
543 mov -4(itmp1),itmp1 /* rplpoint * */
544 push sp /* arg1: execution state */
545 push itmp1 /* arg0: replacement point */
546 call replace_me /* call C function replace_me */
549 /* asm_replacement_in **********************************************************
551 This code writes the given execution state and jumps to the replacement
554 This function never returns!
557 void asm_replacement_in(executionstate *es, replace_safestack_t *st);
559 *******************************************************************************/
563 mov 8(sp),%esi /* replace_safestack_t *st */
564 mov 4(sp),%ebp /* executionstate *es == safe stack */
566 /* switch to the safe stack and build a stack frame */
570 /* call replace_build_execution_state(st) */
572 call replace_build_execution_state
575 mov (offes_sp)(%ebp),sp
577 /* push address of new code */
578 push (offes_pc)(%ebp)
580 /* allocate an executionstate_t on the stack */
581 sub $(sizeexecutionstate),sp
583 /* call replace_free_safestack(st,& of allocated executionstate_t) */
586 call replace_free_safestack
589 /* copy registers from execution state */
590 mov (EAX*4+offes_intregs)(sp),%eax
591 mov (EBX*4+offes_intregs)(sp),%ebx
592 mov (ECX*4+offes_intregs)(sp),%ecx
593 mov (EDX*4+offes_intregs)(sp),%edx
594 mov (ESI*4+offes_intregs)(sp),%esi
595 mov (EDI*4+offes_intregs)(sp),%edi
596 mov (EBP*4+offes_intregs)(sp),%ebp
598 /* pop the execution state off the stack */
599 add $(sizeexecutionstate),sp
601 /* jump to new code, hold your thumbs! ;) */
604 #endif /* defined(ENABLE_REPLACEMENT) */
607 /************************ function asm_builtin_x2x *****************************
609 * Wrapper functions for corner cases *
611 *******************************************************************************/
642 /* asm_compare_and_swap ********************************************************
644 Does an atomic compare and swap. Required for the lock
647 Atomically do the following: Check if the location still contains
648 `oldval`. If so, replace it by `newval` and return `oldval`.
653 long compare_and_swap(volatile long *p, long oldval, long newval);
655 *******************************************************************************/
657 asm_compare_and_swap:
658 mov 1*4(sp),%ecx /* load p into a register */
659 mov 2*4(sp),%eax /* load oldval into return register */
660 mov 3*4(sp),%edx /* load newval into a register */
661 lock; cmpxchgl %edx,0(%ecx)
665 /* asm_memory_barrier **********************************************************
667 A memory barrier for the Java Memory Model.
669 *******************************************************************************/
676 asm_getclassvalues_atomic:
678 mov 4(%esp),%ecx /* super */
679 mov 8(%esp),%edx /* sub */
681 mov offbaseval(%ecx),%eax
682 mov offdiffval(%ecx),%ecx
683 mov offbaseval(%edx),%edx
686 mov 16(%esp),%ebx /* out */
687 mov %eax,offcast_super_baseval(%ebx)
688 mov %ecx,offcast_super_diffval(%ebx)
689 mov %edx,offcast_sub_baseval(%ebx)
695 asm_criticalsections:
696 #if defined(ENABLE_THREADS)
709 /* Disable exec-stacks, required for Gentoo ***********************************/
711 #if defined(__GCC__) && defined(__ELF__)
712 .section .note.GNU-stack,"",@progbits
716 /* asm_get_cycle_count *********************************************************
718 Get the current time-stamp counter from the CPU.
720 *******************************************************************************/
728 * These are local overrides for various environment variables in Emacs.
729 * Please do not remove this and leave it at the end of the file, where
730 * Emacs will automagically detect them.
731 * ---------------------------------------------------------------------
734 * indent-tabs-mode: t
738 * vim:noexpandtab:sw=4:ts=4: