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 4623 2006-03-16 00:05:18Z 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 %esp,%ebp /* save stackptr */
150 push %ebx /* save registers */
154 mov 4*4(%ebp),%eax /* pointer to arg block (4(push)+4(return)+4+4)*/
155 mov 3*4(%ebp),%ecx /* arg count (4(push)+4(return)+4 */
157 xor %esi,%esi /* clear stackframe size (MUST be */
158 /* before args check, may be zero!!!) */
159 test %ecx,%ecx /* maybe we have no args */
160 jle calljava_copydone
162 mov %ecx,%edx /* calculate stack size */
163 mov %eax,%edi /* save pointer to arg block */
165 calljava_calcstacksize:
166 mov offvmargtype(%eax),%ebx
167 test $1,%ebx /* two word type? */
168 jz calljava_onewordtype
169 add $4,%esi /* add 1 slot to stackframe size */
171 calljava_onewordtype:
172 add $4,%esi /* add 1 slot to stackframe size */
174 test %edx,%edx /* any args left? */
176 add $sizevmarg,%eax /* goto next argument block */
177 jmp calljava_calcstacksize
180 mov %edi,%eax /* restore pointer to arg block */
181 sub %esi,%esp /* create stackframe for arguments */
182 mov %esp,%edi /* move stackpointer into temp variable */
185 mov offvmargdata(%eax),%edx /* copy 4 Byte of Argument */
187 add $4,%edi /* increase sp to next argument */
188 mov offvmargtype(%eax),%ebx /* type -> ebx */
189 test $1,%ebx /* two word type? */
192 mov offvmargdata+4(%eax),%edx /* copy upper 4 byte of 2 word type */
194 add $4,%edi /* increase sp to next argument */
197 sub $1,%ecx /* are there any args left? */
199 jle calljava_copydone
201 add $sizevmarg,%eax /* goto next argument block */
202 jmp calljava_copyloop
205 mov 2*4(%ebp),itmp1 /* move function pointer to itmp1 */
207 lea L_asm_call_jit_compiler,itmp3
208 call *itmp3 /* call JIT compiler */
210 L_asm_vm_call_method_return:
211 add %esi,%esp /* remove arg stack frame */
212 pop %edi /* restore registers */
219 push xptr /* pass exception pointer */
220 call builtin_throw_exception
222 xor v0,v0 /* return NULL */
223 jmp L_asm_vm_call_method_return
226 /* asm_call_jit_compiler *******************************************************
228 Invokes the compiler for untranslated JavaVM methods.
230 Register R0 contains a pointer to the method info structure (prepared
231 by createcompilerstub). Using the return address in R26 and the
232 offset in the LDA instruction or using the value in methodptr R28 the
233 patching address for storing the method address can be computed:
235 Method address was either loaded using
237 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
238 i386_call_reg(REG_ITMP2)
242 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
243 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
244 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
245 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
246 i386_call_reg(REG_ITMP1)
248 In the static case the method pointer can be computed using the
249 return address and the lda function following the jmp instruction.
251 *******************************************************************************/
253 asm_call_jit_compiler:
254 L_asm_call_jit_compiler: /* required for PIC code */
255 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
256 mov itmp1,(4+0)*4(sp) /* save method pointer */
258 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
259 mov -1(itmp3),itmp1b /* get function code */
260 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
261 jne L_not_static_special
263 sub $6,itmp3 /* calculate address of immediate */
264 jmp L_call_jit_compile
266 L_not_static_special:
267 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
268 jne L_not_virtual_interface
270 sub $6,itmp3 /* calculate address of offset */
271 mov (itmp3),itmp3 /* get offset */
272 add itmp2,itmp3 /* add base address to get method adr */
273 jmp L_call_jit_compile
275 L_not_virtual_interface:
276 xor itmp3,itmp3 /* a call from asm_calljavafunction */
279 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
281 mov sp,itmp1 /* create stackframe info */
283 mov itmp1,0*4(sp) /* stackframeinfo pointer */
284 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
286 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
288 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
290 call stacktrace_create_inline_stackframeinfo
292 mov (4+0)*4(sp),itmp1 /* pass method pointer */
295 mov v0,(4+0)*4(sp) /* save return value */
297 mov sp,itmp1 /* remove stackframe info */
299 mov itmp1,0*4(sp) /* stackframeinfo pointer */
300 call stacktrace_remove_stackframeinfo
302 mov (4+0)*4(sp),v0 /* restore return value */
303 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
305 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
307 test v0,v0 /* check for exception */
308 je L_asm_call_jit_compiler_exception
310 test itmp3,itmp3 /* was this a JIT call? */
313 mov v0,(itmp3) /* save the new method pointer */
316 jmp *v0 /* ...and now call the new method */
318 L_asm_call_jit_compiler_exception:
319 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
320 call builtin_asm_get_exceptionptrptr
321 mov v0,itmp2 /* v0 == itmp1 */
323 lea _exceptionptr,itmp2
325 mov (itmp2),xptr /* get the exception pointer */
326 movl $0,(itmp2) /* clear the exception pointer */
328 pop xpc /* get return address */
329 sub $2,xpc /* faulting address is ra - 2 */
330 jmp L_asm_handle_exception
333 /* asm_handle_exception ********************************************************
335 * This function handles an exception. It does not use the usual calling *
336 * conventions. The exception pointer is passed in REG_ITMP1 and the *
337 * pc from the exception raising position is passed in REG_ITMP2. It searches *
338 * the local exception table for a handler. If no one is found, it unwinds *
339 * stacks and continues searching the callers. *
341 *******************************************************************************/
343 asm_handle_nat_exception:
344 add $4,sp /* clear return address of native stub*/
346 asm_handle_exception:
347 L_asm_handle_exception: /* required for PIC code */
348 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
350 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
351 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
353 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
354 mov $1,t0 /* set maybe-leaf flag */
356 L_asm_handle_exception_stack_loop:
357 sub $(10*4),sp /* create stackframe */
358 mov xptr,4*4(sp) /* save exception pointer */
359 mov xpc,5*4(sp) /* save exception pc */
360 add sp,itmp3 /* calculate Java sp into a3... */
362 mov itmp3,7*4(sp) /* ...and save it */
363 mov t0,8*4(sp) /* save maybe-leaf flag */
365 mov xpc,0*4(sp) /* pass exception pc */
366 call codegen_findmethod
367 mov v0,6*4(sp) /* save data segment pointer */
369 mov 4*4(sp),itmp3 /* pass exception pointer */
371 mov 5*4(sp),itmp3 /* pass exception pc */
373 mov v0,2*4(sp) /* pass data segment pointer */
374 mov 7*4(sp),itmp3 /* pass Java stack pointer */
376 call exceptions_handle_exception
379 jz L_asm_handle_exception_not_catched
381 mov v0,xpc /* move handlerpc into xpc */
382 mov 4*4(sp),xptr /* restore exception pointer */
383 mov 8*4(sp),t0 /* get maybe-leaf flag */
384 add $(10*4),sp /* free stackframe */
386 test t0,t0 /* test for maybe-leaf flag */
387 jz L_asm_handle_exception_no_leaf
389 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
390 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
392 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
394 L_asm_handle_exception_no_leaf:
395 jmp *xpc /* jump to exception handler */
397 L_asm_handle_exception_not_catched:
398 mov 4*4(sp),xptr /* restore exception pointer */
399 mov 6*4(sp),itmp3 /* restore data segment pointer */
400 mov 8*4(sp),t0 /* get maybe-leaf flag */
401 add $(10*4),sp /* free stackframe */
404 jz L_asm_handle_exception_no_leaf_stack
406 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
407 xor t0,t0 /* clear the maybe-leaf flag */
409 L_asm_handle_exception_no_leaf_stack:
410 mov FrameSize(itmp3),itmp2 /* get frame size */
411 add sp,itmp2 /* pointer to save area */
413 push xptr /* we are out of registers */
415 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
430 shl $2,itmp1 /* multiply by 4 bytes */
435 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
460 pop xptr /* restore exception pointer */
461 mov FrameSize(itmp3),itmp2 /* get frame size */
462 add itmp2,sp /* unwind stack */
464 pop xpc /* the new xpc is return address */
465 sub $2,xpc /* subtract 2-bytes for call */
467 xor itmp3,itmp3 /* prepare a3 for handle_exception */
469 jmp L_asm_handle_exception_stack_loop
472 /* asm_wrapper_patcher *********************************************************
479 16 pointer to virtual java_objectheader
480 12 last byte of machine code (xmcode)
481 8 machine code (which is patched back later)
482 4 unresolved field reference
483 0 patcher function pointer to call
485 *******************************************************************************/
488 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
490 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
491 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
493 mov sp,itmp1 /* create stackframe info */
495 mov itmp1,0*4(sp) /* stackframeinfo pointer */
496 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
498 add $((7+2+4)*4+sizestackframeinfo),itmp2
499 mov itmp2,2*4(sp) /* pass Java sp */
500 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
501 mov itmp3,3*4(sp) /* pass ra to java function */
502 call stacktrace_create_inline_stackframeinfo
504 mov sp,itmp1 /* pass stack pointer */
505 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
507 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
508 call *itmp1 /* call the patcher function */
509 mov v0,1*4(sp) /* save return value */
511 mov sp,itmp1 /* remove stackframe info */
513 mov itmp1,0*4(sp) /* stackframeinfo pointer */
514 call stacktrace_remove_stackframeinfo
516 mov 1*4(sp),itmp3 /* restore return value */
517 test itmp3,itmp3 /* exception thrown? */
518 jz L_asm_wrapper_patcher_exception
520 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
521 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
522 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
523 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
525 ret /* call new patched code */
527 L_asm_wrapper_patcher_exception:
528 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
530 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
531 call builtin_asm_get_exceptionptrptr
534 lea _exceptionptr,itmp2
536 mov (itmp2),xptr /* get the exception pointer */
537 movl $0,(itmp2) /* clear the exception pointer */
539 pop xpc /* get and remove return address */
540 jmp L_asm_handle_exception
543 /* asm_replacement_out *********************************************************
545 This code is jumped to from the replacement-out stubs that are executed
546 when a thread reaches an activated replacement point.
548 The purpose of asm_replacement_out is to read out the parts of the
549 execution state that cannot be accessed from C code, store this state,
550 and then call the C function replace_me.
553 4 start of stack inside method to replace
554 0 rplpoint * info on the replacement point that was reached
556 *******************************************************************************/
558 /* some room to accomodate changes of the stack frame size during replacement */
559 /* XXX we should find a cleaner solution here */
560 #define REPLACEMENT_ROOM 512
563 /* create stack frame */
564 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
566 /* save registers in execution state */
567 mov %eax,(EAX*8+offes_intregs)(sp)
568 mov %ebx,(EBX*8+offes_intregs)(sp)
569 mov %ecx,(ECX*8+offes_intregs)(sp)
570 mov %edx,(EDX*8+offes_intregs)(sp)
571 mov %esi,(ESI*8+offes_intregs)(sp)
572 mov %edi,(EDI*8+offes_intregs)(sp)
573 mov %ebp,(EBP*8+offes_intregs)(sp)
574 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
577 /* clear high 32bit */
578 movl $0,(4+0*8+offes_intregs)(sp)
579 movl $0,(4+1*8+offes_intregs)(sp)
580 movl $0,(4+2*8+offes_intregs)(sp)
581 movl $0,(4+3*8+offes_intregs)(sp)
582 movl $0,(4+4*8+offes_intregs)(sp)
583 movl $0,(4+5*8+offes_intregs)(sp)
584 movl $0,(4+6*8+offes_intregs)(sp)
585 movl $0,(4+7*8+offes_intregs)(sp)
588 /* calculate sp of method */
590 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
591 mov itmp1,(offes_sp)(sp)
593 /* call replace_me */
594 mov -4(itmp1),itmp1 /* rplpoint * */
595 push sp /* arg1: execution state */
596 push itmp1 /* arg0: replacement point */
597 call replace_me /* call C function replace_me */
598 call abort /* NEVER REACHED */
600 /* asm_replacement_in **********************************************************
602 This code writes the given execution state and jumps to the replacement
605 This function never returns!
608 void asm_replacement_in(executionstate *es);
610 *******************************************************************************/
613 mov 4(sp),%ebp /* executionstate *es */
616 mov (offes_sp)(%ebp),%esp
618 /* store address of new code */
619 push (offes_pc)(%ebp)
621 /* copy registers from execution state */
622 mov (EAX*8+offes_intregs)(%ebp),%eax
623 mov (EBX*8+offes_intregs)(%ebp),%ebx
624 mov (ECX*8+offes_intregs)(%ebp),%ecx
625 mov (EDX*8+offes_intregs)(%ebp),%edx
626 mov (ESI*8+offes_intregs)(%ebp),%esi
627 mov (EDI*8+offes_intregs)(%ebp),%edi
629 mov (EBP*8+offes_intregs)(%ebp),%ebp
631 /* jump to new code */
634 /************************ function asm_builtin_x2x *****************************
636 * Wrapper functions for corner cases *
638 *******************************************************************************/
669 /******************* function asm_initialize_thread_stack **********************
671 * initialized a thread stack *
672 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
674 *******************************************************************************/
676 asm_initialize_thread_stack:
677 mov 8(%esp),%eax /* (to)->stackEnd */
678 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
690 mov 4(%esp),%edx /* save (u1*) (func) */
693 ret /* return restorepoint in %eax */
696 /******************* function asm_perform_threadswitch *************************
698 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
700 * performs a threadswitch *
702 *******************************************************************************/
704 asm_perform_threadswitch:
716 mov 36(%esp),%eax /* save current return address */
719 mov 40(%esp),%eax /* first argument **from */
722 mov 48(%esp),%eax /* third argument **stackTop */
725 mov 44(%esp),%eax /* second argument **to */
726 mov 0(%eax),%esp /* load new stack pointer */
732 /* skip stack pointer */
737 add $32,%esp /* leave return address on stack */
741 /********************* function asm_switchstackandcall *************************
743 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
746 * Switches to a new stack, calls a function and switches back. *
747 * a0 new stack pointer *
748 * a1 function pointer *
749 * a2 pointer to variable where stack top should be stored *
750 * a3 pointer to user data, is passed to the function *
752 *******************************************************************************/
754 asm_switchstackandcall:
755 mov 4(%esp),%edx /* first argument *stack */
756 sub $8,%edx /* allocate new stack */
758 mov (%esp),%eax /* save return address on new stack */
761 mov %esp,4(%edx) /* save old stack pointer on new stack */
763 mov 12(%esp),%eax /* third argument **stacktopsave */
764 mov %esp,(%eax) /* save old stack pointer to variable */
766 mov 8(%esp),%eax /* load function pointer */
767 mov 16(%esp),%ecx /* fourth argument *p */
769 mov %edx,%esp /* switch to new stack */
772 mov %ecx,0(%esp) /* pass pointer */
773 call *%eax /* and call function */
776 mov (%esp),%edx /* load return address */
777 mov 4(%esp),%esp /* switch to old stack */
782 asm_getclassvalues_atomic:
784 mov 4(%esp),%ecx /* super */
785 mov 8(%esp),%edx /* sub */
787 mov offbaseval(%ecx),%eax
788 mov offdiffval(%ecx),%ecx
789 mov offbaseval(%edx),%edx
792 mov 16(%esp),%ebx /* out */
793 mov %eax,offcast_super_baseval(%ebx)
794 mov %ecx,offcast_super_diffval(%ebx)
795 mov %edx,offcast_sub_baseval(%ebx)
801 asm_criticalsections:
802 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
815 /* Disable exec-stacks, required for Gentoo ***********************************/
817 #if defined(__GCC__) && defined(__ELF__)
818 .section .note.GNU-stack,"",@progbits
823 * These are local overrides for various environment variables in Emacs.
824 * Please do not remove this and leave it at the end of the file, where
825 * Emacs will automagically detect them.
826 * ---------------------------------------------------------------------
829 * indent-tabs-mode: t
833 * vim:noexpandtab:sw=4:ts=4: