1 /* src/vm/jit/i386/asmpart.S - Java-C interface functions for i386
3 Copyright (C) 1996-2005, 2006 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 Contact: cacao@cacaojvm.org
27 Authors: Andreas Krall
31 Changes: Joseph Wenninger
34 $Id: asmpart.S 4677 2006-03-22 20:59:49Z edwin $
41 #include "vm/jit/abi.h"
42 #include "vm/jit/i386/md-abi.h"
43 #include "vm/jit/i386/md-asm.h"
44 #include "vm/jit/i386/offsets.h"
45 #include "vm/jit/i386/arch.h"
47 #include "vm/jit/methodheader.h"
53 /* exported functions and variables *******************************************/
57 .globl asm_vm_call_method
58 .globl asm_vm_call_method_int
59 .globl asm_vm_call_method_long
60 .globl asm_vm_call_method_float
61 .globl asm_vm_call_method_double
63 .globl asm_call_jit_compiler
64 .globl asm_handle_nat_exception
65 .globl asm_handle_exception
67 .globl asm_wrapper_patcher
69 .globl asm_replacement_out
70 .globl asm_replacement_in
72 .globl asm_builtin_f2i
73 .globl asm_builtin_f2l
74 .globl asm_builtin_d2i
75 .globl asm_builtin_d2l
77 .globl asm_perform_threadswitch
78 .globl asm_initialize_thread_stack
79 .globl asm_switchstackandcall
80 .globl asm_criticalsections
81 .globl asm_getclassvalues_atomic
84 /* asm_md_init *****************************************************************
86 Initialize machine dependent stuff.
88 See: http://www.srware.com/linux_numerics.txt
90 This puts the X86 FPU in 64-bit precision mode. The default under
91 Linux is to use 80-bit mode, which produces subtle differences from
92 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
93 64-bit mode, 299 in 80-bit mode.
95 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
97 *******************************************************************************/
100 sub $4,sp /* allocate space for the FPU state */
101 fnstcw (sp) /* get the FPU state */
103 and $0xfcff,%ax /* remove the extended mode flag */
104 or $0x0200,%ax /* put the double mode flag */
105 mov %eax,(sp) /* store new FPU state */
106 fldcw (sp) /* setup new FPU state */
111 /********************* function asm_calljavafunction ***************************
113 * This function calls a Java-method (which possibly needs compilation) *
114 * with up to 4 address parameters. *
116 * This functions calls the JIT-compiler which eventually translates the *
117 * method into machine code. *
120 * javaobject_header *asm_vm_call_method(methodinfo *m, *
121 * u4 count, u4 size, void *callblock); *
123 *******************************************************************************/
127 .long 0 /* catch type all */
128 .long calljava_xhandler2 /* handler pc */
129 .long calljava_xhandler2 /* end pc */
130 .long L_asm_vm_call_method /* start pc */
131 .long 1 /* extable size */
132 .long 0 /* line number table start */
133 .long 0 /* line number table size */
134 .long 0 /* fltsave */
135 .long 0 /* intsave */
138 .long 0 /* frame size */
139 .long 0 /* method pointer (pointer to name) */
142 asm_vm_call_method_int:
143 asm_vm_call_method_long:
144 asm_vm_call_method_float:
145 asm_vm_call_method_double:
146 L_asm_vm_call_method: /* required for PIC code */
148 mov sp,bp /* save stackptr */
149 sub $(4*4),sp /* create stackframe */
150 and $0xfffffff0,sp /* align stack to 16-byte */
152 mov t0,0*4(sp) /* save registers */
156 mov 4*4(bp),itmp1 /* pointer to arg block (4(push)+4(return)+4+4)*/
157 mov 3*4(bp),itmp2 /* arg count (4(push)+4(return)+4 */
159 mov sp,s1 /* save the stackpointer */
161 test itmp2,itmp2 /* maybe we have no args */
162 jle calljava_copydone
164 mov itmp2,itmp3 /* calculate stack size */
165 mov itmp1,%edi /* save pointer to arg block */
167 calljava_calcstacksize:
168 mov offvmargtype(itmp1),t0
169 test $1,t0 /* two word type? */
170 jz calljava_onewordtype
172 sub $4,sp /* add 1 slot to stackframe size */
174 calljava_onewordtype:
175 sub $4,sp /* add 1 slot to stackframe size */
177 test itmp3,itmp3 /* any args left? */
180 add $sizevmarg,itmp1 /* goto next argument block */
181 jmp calljava_calcstacksize
184 mov %edi,itmp1 /* restore pointer to arg block */
185 and $0xfffffff0,sp /* align stack to 16-byte */
186 mov sp,itmp3 /* initialize pointer for copying */
189 mov offvmargdata(itmp1),t0 /* get 4-bytes of argument */
190 mov t0,(itmp3) /* and store them on the stack */
191 add $4,itmp3 /* increase sp to next argument */
192 mov offvmargtype(itmp1),t0 /* get the argument type */
193 test $1,t0 /* two word type? */
196 mov offvmargdata+4(itmp1),t0 /* get upper 4-bytes of 2 word type */
198 add $4,itmp3 /* increase sp to next argument */
201 sub $1,itmp2 /* are there any args left? */
203 jle calljava_copydone
205 add $sizevmarg,itmp1 /* goto next argument block */
206 jmp calljava_copyloop
209 mov 2*4(bp),itmp1 /* move function pointer to itmp1 */
211 lea L_asm_call_jit_compiler,itmp3
212 call *itmp3 /* call JIT compiler */
214 L_asm_vm_call_method_return:
215 mov s1,sp /* restore stackpointer */
217 mov 0*4(sp),t0 /* restore registers */
225 push xptr /* pass exception pointer */
226 call builtin_throw_exception
228 xor v0,v0 /* return NULL */
229 jmp L_asm_vm_call_method_return
232 /* asm_call_jit_compiler *******************************************************
234 Invokes the compiler for untranslated JavaVM methods.
236 Register R0 contains a pointer to the method info structure (prepared
237 by createcompilerstub). Using the return address in R26 and the
238 offset in the LDA instruction or using the value in methodptr R28 the
239 patching address for storing the method address can be computed:
241 Method address was either loaded using
243 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
244 i386_call_reg(REG_ITMP2)
248 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
249 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
250 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
251 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
252 i386_call_reg(REG_ITMP1)
254 In the static case the method pointer can be computed using the
255 return address and the lda function following the jmp instruction.
257 *******************************************************************************/
259 asm_call_jit_compiler:
260 L_asm_call_jit_compiler: /* required for PIC code */
261 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
262 mov itmp1,(4+0)*4(sp) /* save method pointer */
264 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
265 mov -1(itmp3),itmp1b /* get function code */
266 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
267 jne L_not_static_special
269 sub $6,itmp3 /* calculate address of immediate */
270 jmp L_call_jit_compile
272 L_not_static_special:
273 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
274 jne L_not_virtual_interface
276 sub $6,itmp3 /* calculate address of offset */
277 mov (itmp3),itmp3 /* get offset */
278 add itmp2,itmp3 /* add base address to get method adr */
279 jmp L_call_jit_compile
281 L_not_virtual_interface:
282 xor itmp3,itmp3 /* a call from asm_calljavafunction */
285 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
287 mov sp,itmp1 /* create stackframe info */
289 mov itmp1,0*4(sp) /* stackframeinfo pointer */
290 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
292 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
294 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
296 call stacktrace_create_inline_stackframeinfo
298 mov (4+0)*4(sp),itmp1 /* pass method pointer */
301 mov v0,(4+0)*4(sp) /* save return value */
303 mov sp,itmp1 /* remove stackframe info */
305 mov itmp1,0*4(sp) /* stackframeinfo pointer */
306 call stacktrace_remove_stackframeinfo
308 mov (4+0)*4(sp),v0 /* restore return value */
309 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
311 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
313 test v0,v0 /* check for exception */
314 je L_asm_call_jit_compiler_exception
316 test itmp3,itmp3 /* was this a JIT call? */
319 mov v0,(itmp3) /* save the new method pointer */
322 jmp *v0 /* ...and now call the new method */
324 L_asm_call_jit_compiler_exception:
325 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
326 call builtin_asm_get_exceptionptrptr
327 mov v0,itmp2 /* v0 == itmp1 */
329 lea _exceptionptr,itmp2
331 mov (itmp2),xptr /* get the exception pointer */
332 movl $0,(itmp2) /* clear the exception pointer */
334 pop xpc /* get return address */
335 sub $2,xpc /* faulting address is ra - 2 */
336 jmp L_asm_handle_exception
339 /* asm_handle_exception ********************************************************
341 * This function handles an exception. It does not use the usual calling *
342 * conventions. The exception pointer is passed in REG_ITMP1 and the *
343 * pc from the exception raising position is passed in REG_ITMP2. It searches *
344 * the local exception table for a handler. If no one is found, it unwinds *
345 * stacks and continues searching the callers. *
347 *******************************************************************************/
349 asm_handle_nat_exception:
350 add $4,sp /* clear return address of native stub*/
352 asm_handle_exception:
353 L_asm_handle_exception: /* required for PIC code */
354 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
356 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
357 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
359 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
360 mov $1,t0 /* set maybe-leaf flag */
362 L_asm_handle_exception_stack_loop:
363 sub $(10*4),sp /* create stackframe */
364 mov xptr,4*4(sp) /* save exception pointer */
365 mov xpc,5*4(sp) /* save exception pc */
366 add sp,itmp3 /* calculate Java sp into a3... */
368 mov itmp3,7*4(sp) /* ...and save it */
369 mov t0,8*4(sp) /* save maybe-leaf flag */
371 mov xpc,0*4(sp) /* pass exception pc */
372 call codegen_findmethod
373 mov v0,6*4(sp) /* save data segment pointer */
375 mov 4*4(sp),itmp3 /* pass exception pointer */
377 mov 5*4(sp),itmp3 /* pass exception pc */
379 mov v0,2*4(sp) /* pass data segment pointer */
380 mov 7*4(sp),itmp3 /* pass Java stack pointer */
382 call exceptions_handle_exception
385 jz L_asm_handle_exception_not_catched
387 mov v0,xpc /* move handlerpc into xpc */
388 mov 4*4(sp),xptr /* restore exception pointer */
389 mov 8*4(sp),t0 /* get maybe-leaf flag */
390 add $(10*4),sp /* free stackframe */
392 test t0,t0 /* test for maybe-leaf flag */
393 jz L_asm_handle_exception_no_leaf
395 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
396 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
398 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
400 L_asm_handle_exception_no_leaf:
401 jmp *xpc /* jump to exception handler */
403 L_asm_handle_exception_not_catched:
404 mov 4*4(sp),xptr /* restore exception pointer */
405 mov 6*4(sp),itmp3 /* restore data segment pointer */
406 mov 8*4(sp),t0 /* get maybe-leaf flag */
407 add $(10*4),sp /* free stackframe */
410 jz L_asm_handle_exception_no_leaf_stack
412 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
413 xor t0,t0 /* clear the maybe-leaf flag */
415 L_asm_handle_exception_no_leaf_stack:
416 mov FrameSize(itmp3),itmp2 /* get frame size */
417 add sp,itmp2 /* pointer to save area */
419 push xptr /* we are out of registers */
421 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
436 shl $2,itmp1 /* multiply by 4 bytes */
441 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
466 pop xptr /* restore exception pointer */
467 mov FrameSize(itmp3),itmp2 /* get frame size */
468 add itmp2,sp /* unwind stack */
470 pop xpc /* the new xpc is return address */
471 sub $2,xpc /* subtract 2-bytes for call */
473 xor itmp3,itmp3 /* prepare a3 for handle_exception */
475 jmp L_asm_handle_exception_stack_loop
478 /* asm_wrapper_patcher *********************************************************
485 16 pointer to virtual java_objectheader
486 12 last byte of machine code (xmcode)
487 8 machine code (which is patched back later)
488 4 unresolved field reference
489 0 patcher function pointer to call
491 *******************************************************************************/
494 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
496 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
497 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
499 mov sp,itmp1 /* create stackframe info */
501 mov itmp1,0*4(sp) /* stackframeinfo pointer */
502 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
504 add $((7+2+4)*4+sizestackframeinfo),itmp2
505 mov itmp2,2*4(sp) /* pass Java sp */
506 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
507 mov itmp3,3*4(sp) /* pass ra to java function */
508 call stacktrace_create_inline_stackframeinfo
510 mov sp,itmp1 /* pass stack pointer */
511 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
513 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
514 call *itmp1 /* call the patcher function */
515 mov v0,1*4(sp) /* save return value */
517 mov sp,itmp1 /* remove stackframe info */
519 mov itmp1,0*4(sp) /* stackframeinfo pointer */
520 call stacktrace_remove_stackframeinfo
522 mov 1*4(sp),itmp3 /* restore return value */
523 test itmp3,itmp3 /* exception thrown? */
524 jz L_asm_wrapper_patcher_exception
526 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
527 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
528 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
529 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
531 ret /* call new patched code */
533 L_asm_wrapper_patcher_exception:
534 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
536 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
537 call builtin_asm_get_exceptionptrptr
540 lea _exceptionptr,itmp2
542 mov (itmp2),xptr /* get the exception pointer */
543 movl $0,(itmp2) /* clear the exception pointer */
545 pop xpc /* get and remove return address */
546 jmp L_asm_handle_exception
549 /* asm_replacement_out *********************************************************
551 This code is jumped to from the replacement-out stubs that are executed
552 when a thread reaches an activated replacement point.
554 The purpose of asm_replacement_out is to read out the parts of the
555 execution state that cannot be accessed from C code, store this state,
556 and then call the C function replace_me.
559 4 start of stack inside method to replace
560 0 rplpoint * info on the replacement point that was reached
562 *******************************************************************************/
564 /* some room to accomodate changes of the stack frame size during replacement */
565 /* XXX we should find a cleaner solution here */
566 #define REPLACEMENT_ROOM 512
569 /* create stack frame */
570 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
572 /* save registers in execution state */
573 mov %eax,(EAX*8+offes_intregs)(sp)
574 mov %ebx,(EBX*8+offes_intregs)(sp)
575 mov %ecx,(ECX*8+offes_intregs)(sp)
576 mov %edx,(EDX*8+offes_intregs)(sp)
577 mov %esi,(ESI*8+offes_intregs)(sp)
578 mov %edi,(EDI*8+offes_intregs)(sp)
579 mov %ebp,(EBP*8+offes_intregs)(sp)
580 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
583 /* clear high 32bit */
584 movl $0,(4+0*8+offes_intregs)(sp)
585 movl $0,(4+1*8+offes_intregs)(sp)
586 movl $0,(4+2*8+offes_intregs)(sp)
587 movl $0,(4+3*8+offes_intregs)(sp)
588 movl $0,(4+4*8+offes_intregs)(sp)
589 movl $0,(4+5*8+offes_intregs)(sp)
590 movl $0,(4+6*8+offes_intregs)(sp)
591 movl $0,(4+7*8+offes_intregs)(sp)
594 /* calculate sp of method */
596 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
597 mov itmp1,(offes_sp)(sp)
599 /* pv must be looked up via AVL tree */
600 movl $0,(offes_pv)(sp)
602 /* call replace_me */
603 mov -4(itmp1),itmp1 /* rplpoint * */
604 push sp /* arg1: execution state */
605 push itmp1 /* arg0: replacement point */
606 call replace_me /* call C function replace_me */
607 call abort /* NEVER REACHED */
609 /* asm_replacement_in **********************************************************
611 This code writes the given execution state and jumps to the replacement
614 This function never returns!
617 void asm_replacement_in(executionstate *es);
619 *******************************************************************************/
622 mov 4(sp),%ebp /* executionstate *es */
625 mov (offes_sp)(%ebp),%esp
627 /* store address of new code */
628 push (offes_pc)(%ebp)
630 /* copy registers from execution state */
631 mov (EAX*8+offes_intregs)(%ebp),%eax
632 mov (EBX*8+offes_intregs)(%ebp),%ebx
633 mov (ECX*8+offes_intregs)(%ebp),%ecx
634 mov (EDX*8+offes_intregs)(%ebp),%edx
635 mov (ESI*8+offes_intregs)(%ebp),%esi
636 mov (EDI*8+offes_intregs)(%ebp),%edi
638 mov (EBP*8+offes_intregs)(%ebp),%ebp
640 /* jump to new code */
643 /************************ function asm_builtin_x2x *****************************
645 * Wrapper functions for corner cases *
647 *******************************************************************************/
678 /******************* function asm_initialize_thread_stack **********************
680 * initialized a thread stack *
681 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
683 *******************************************************************************/
685 asm_initialize_thread_stack:
686 mov 8(%esp),%eax /* (to)->stackEnd */
687 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
699 mov 4(%esp),%edx /* save (u1*) (func) */
702 ret /* return restorepoint in %eax */
705 /******************* function asm_perform_threadswitch *************************
707 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
709 * performs a threadswitch *
711 *******************************************************************************/
713 asm_perform_threadswitch:
725 mov 36(%esp),%eax /* save current return address */
728 mov 40(%esp),%eax /* first argument **from */
731 mov 48(%esp),%eax /* third argument **stackTop */
734 mov 44(%esp),%eax /* second argument **to */
735 mov 0(%eax),%esp /* load new stack pointer */
741 /* skip stack pointer */
746 add $32,%esp /* leave return address on stack */
750 /********************* function asm_switchstackandcall *************************
752 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
755 * Switches to a new stack, calls a function and switches back. *
756 * a0 new stack pointer *
757 * a1 function pointer *
758 * a2 pointer to variable where stack top should be stored *
759 * a3 pointer to user data, is passed to the function *
761 *******************************************************************************/
763 asm_switchstackandcall:
764 mov 4(%esp),%edx /* first argument *stack */
765 sub $8,%edx /* allocate new stack */
767 mov (%esp),%eax /* save return address on new stack */
770 mov %esp,4(%edx) /* save old stack pointer on new stack */
772 mov 12(%esp),%eax /* third argument **stacktopsave */
773 mov %esp,(%eax) /* save old stack pointer to variable */
775 mov 8(%esp),%eax /* load function pointer */
776 mov 16(%esp),%ecx /* fourth argument *p */
778 mov %edx,%esp /* switch to new stack */
781 mov %ecx,0(%esp) /* pass pointer */
782 call *%eax /* and call function */
785 mov (%esp),%edx /* load return address */
786 mov 4(%esp),%esp /* switch to old stack */
791 asm_getclassvalues_atomic:
793 mov 4(%esp),%ecx /* super */
794 mov 8(%esp),%edx /* sub */
796 mov offbaseval(%ecx),%eax
797 mov offdiffval(%ecx),%ecx
798 mov offbaseval(%edx),%edx
801 mov 16(%esp),%ebx /* out */
802 mov %eax,offcast_super_baseval(%ebx)
803 mov %ecx,offcast_super_diffval(%ebx)
804 mov %edx,offcast_sub_baseval(%ebx)
810 asm_criticalsections:
811 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
824 /* Disable exec-stacks, required for Gentoo ***********************************/
826 #if defined(__GCC__) && defined(__ELF__)
827 .section .note.GNU-stack,"",@progbits
832 * These are local overrides for various environment variables in Emacs.
833 * Please do not remove this and leave it at the end of the file, where
834 * Emacs will automagically detect them.
835 * ---------------------------------------------------------------------
838 * indent-tabs-mode: t
842 * vim:noexpandtab:sw=4:ts=4: