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 4707 2006-03-30 09:52:49Z twisti $
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 /* export functions ***********************************************************/
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
62 .globl asm_vm_call_method_exception_handler
64 .globl asm_call_jit_compiler
65 .globl asm_handle_nat_exception
66 .globl asm_handle_exception
68 .globl asm_wrapper_patcher
70 .globl asm_replacement_out
71 .globl asm_replacement_in
73 .globl asm_builtin_f2i
74 .globl asm_builtin_f2l
75 .globl asm_builtin_d2i
76 .globl asm_builtin_d2l
78 .globl asm_perform_threadswitch
79 .globl asm_initialize_thread_stack
80 .globl asm_switchstackandcall
81 .globl asm_criticalsections
82 .globl asm_getclassvalues_atomic
85 /* asm_md_init *****************************************************************
87 Initialize machine dependent stuff.
89 See: http://www.srware.com/linux_numerics.txt
91 This puts the X86 FPU in 64-bit precision mode. The default under
92 Linux is to use 80-bit mode, which produces subtle differences from
93 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
94 64-bit mode, 299 in 80-bit mode.
96 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
98 *******************************************************************************/
101 sub $4,sp /* allocate space for the FPU state */
102 fnstcw (sp) /* get the FPU state */
104 and $0xfcff,%ax /* remove the extended mode flag */
105 or $0x0200,%ax /* put the double mode flag */
106 mov %eax,(sp) /* store new FPU state */
107 fldcw (sp) /* setup new FPU state */
112 /********************* function asm_calljavafunction ***************************
114 * This function calls a Java-method (which possibly needs compilation) *
115 * with up to 4 address parameters. *
117 * This functions calls the JIT-compiler which eventually translates the *
118 * method into machine code. *
121 * javaobject_header *asm_vm_call_method(methodinfo *m, *
122 * u4 count, u4 size, void *callblock); *
124 *******************************************************************************/
128 .long 0 /* catch type all */
129 .long 0 /* handler pc */
131 .long 0 /* start pc */
132 .long 1 /* extable size */
133 .long 0 /* line number table start */
134 .long 0 /* line number table size */
135 .long 0 /* fltsave */
136 .long 0 /* intsave */
139 .long 0 /* frame size */
140 .long 0 /* method pointer (pointer to name) */
143 asm_vm_call_method_int:
144 asm_vm_call_method_long:
145 asm_vm_call_method_float:
146 asm_vm_call_method_double:
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 */
224 asm_vm_call_method_exception_handler:
226 push xptr /* pass exception pointer */
227 call builtin_throw_exception
230 xor v0,v0 /* return NULL */
231 jmp L_asm_vm_call_method_return
234 /* asm_call_jit_compiler *******************************************************
236 Invokes the compiler for untranslated JavaVM methods.
238 Register R0 contains a pointer to the method info structure (prepared
239 by createcompilerstub). Using the return address in R26 and the
240 offset in the LDA instruction or using the value in methodptr R28 the
241 patching address for storing the method address can be computed:
243 Method address was either loaded using
245 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
246 i386_call_reg(REG_ITMP2)
250 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
251 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
252 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
253 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
254 i386_call_reg(REG_ITMP1)
256 In the static case the method pointer can be computed using the
257 return address and the lda function following the jmp instruction.
259 *******************************************************************************/
261 asm_call_jit_compiler:
262 L_asm_call_jit_compiler: /* required for PIC code */
263 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
264 mov itmp1,(4+0)*4(sp) /* save method pointer */
266 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
267 mov -1(itmp3),itmp1b /* get function code */
268 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
269 jne L_not_static_special
271 sub $6,itmp3 /* calculate address of immediate */
272 jmp L_call_jit_compile
274 L_not_static_special:
275 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
276 jne L_not_virtual_interface
278 sub $6,itmp3 /* calculate address of offset */
279 mov (itmp3),itmp3 /* get offset */
280 add itmp2,itmp3 /* add base address to get method adr */
281 jmp L_call_jit_compile
283 L_not_virtual_interface:
284 xor itmp3,itmp3 /* a call from asm_calljavafunction */
287 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
289 mov sp,itmp1 /* create stackframe info */
291 mov itmp1,0*4(sp) /* stackframeinfo pointer */
292 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
294 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
296 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
298 call stacktrace_create_inline_stackframeinfo
300 mov (4+0)*4(sp),itmp1 /* pass method pointer */
303 mov v0,(4+0)*4(sp) /* save return value */
305 mov sp,itmp1 /* remove stackframe info */
307 mov itmp1,0*4(sp) /* stackframeinfo pointer */
308 call stacktrace_remove_stackframeinfo
310 mov (4+0)*4(sp),v0 /* restore return value */
311 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
313 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
315 test v0,v0 /* check for exception */
316 je L_asm_call_jit_compiler_exception
318 test itmp3,itmp3 /* was this a JIT call? */
321 mov v0,(itmp3) /* save the new method pointer */
324 jmp *v0 /* ...and now call the new method */
326 L_asm_call_jit_compiler_exception:
327 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
328 call builtin_asm_get_exceptionptrptr
329 mov v0,itmp2 /* v0 == itmp1 */
331 lea _exceptionptr,itmp2
333 mov (itmp2),xptr /* get the exception pointer */
334 movl $0,(itmp2) /* clear the exception pointer */
336 pop xpc /* get return address */
337 sub $2,xpc /* faulting address is ra - 2 */
338 jmp L_asm_handle_exception
341 /* asm_handle_exception ********************************************************
343 * This function handles an exception. It does not use the usual calling *
344 * conventions. The exception pointer is passed in REG_ITMP1 and the *
345 * pc from the exception raising position is passed in REG_ITMP2. It searches *
346 * the local exception table for a handler. If no one is found, it unwinds *
347 * stacks and continues searching the callers. *
349 *******************************************************************************/
351 asm_handle_nat_exception:
352 add $4,sp /* clear return address of native stub*/
354 asm_handle_exception:
355 L_asm_handle_exception: /* required for PIC code */
356 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
358 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
359 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
361 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
362 mov $1,t0 /* set maybe-leaf flag */
364 L_asm_handle_exception_stack_loop:
365 sub $(10*4),sp /* create stackframe */
366 mov xptr,4*4(sp) /* save exception pointer */
367 mov xpc,5*4(sp) /* save exception pc */
368 add sp,itmp3 /* calculate Java sp into a3... */
370 mov itmp3,7*4(sp) /* ...and save it */
371 mov t0,8*4(sp) /* save maybe-leaf flag */
373 mov xpc,0*4(sp) /* pass exception pc */
374 call codegen_findmethod
375 mov v0,6*4(sp) /* save data segment pointer */
377 mov 4*4(sp),itmp3 /* pass exception pointer */
379 mov 5*4(sp),itmp3 /* pass exception pc */
381 mov v0,2*4(sp) /* pass data segment pointer */
382 mov 7*4(sp),itmp3 /* pass Java stack pointer */
384 call exceptions_handle_exception
387 jz L_asm_handle_exception_not_catched
389 mov v0,xpc /* move handlerpc into xpc */
390 mov 4*4(sp),xptr /* restore exception pointer */
391 mov 8*4(sp),t0 /* get maybe-leaf flag */
392 add $(10*4),sp /* free stackframe */
394 test t0,t0 /* test for maybe-leaf flag */
395 jz L_asm_handle_exception_no_leaf
397 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
398 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
400 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
402 L_asm_handle_exception_no_leaf:
403 jmp *xpc /* jump to exception handler */
405 L_asm_handle_exception_not_catched:
406 mov 4*4(sp),xptr /* restore exception pointer */
407 mov 6*4(sp),itmp3 /* restore data segment pointer */
408 mov 8*4(sp),t0 /* get maybe-leaf flag */
409 add $(10*4),sp /* free stackframe */
412 jz L_asm_handle_exception_no_leaf_stack
414 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
415 xor t0,t0 /* clear the maybe-leaf flag */
417 L_asm_handle_exception_no_leaf_stack:
418 mov FrameSize(itmp3),itmp2 /* get frame size */
419 add sp,itmp2 /* pointer to save area */
421 push xptr /* we are out of registers */
423 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
438 shl $2,itmp1 /* multiply by 4 bytes */
443 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
468 pop xptr /* restore exception pointer */
469 mov FrameSize(itmp3),itmp2 /* get frame size */
470 add itmp2,sp /* unwind stack */
472 pop xpc /* the new xpc is return address */
473 sub $2,xpc /* subtract 2-bytes for call */
475 xor itmp3,itmp3 /* prepare a3 for handle_exception */
477 jmp L_asm_handle_exception_stack_loop
480 /* asm_wrapper_patcher *********************************************************
487 16 pointer to virtual java_objectheader
488 12 last byte of machine code (xmcode)
489 8 machine code (which is patched back later)
490 4 unresolved field reference
491 0 patcher function pointer to call
493 *******************************************************************************/
496 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
498 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
499 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
501 mov sp,itmp1 /* create stackframe info */
503 mov itmp1,0*4(sp) /* stackframeinfo pointer */
504 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
506 add $((7+2+4)*4+sizestackframeinfo),itmp2
507 mov itmp2,2*4(sp) /* pass Java sp */
508 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
509 mov itmp3,3*4(sp) /* pass ra to java function */
510 call stacktrace_create_inline_stackframeinfo
512 mov sp,itmp1 /* pass stack pointer */
513 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
515 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
516 call *itmp1 /* call the patcher function */
517 mov v0,1*4(sp) /* save return value */
519 mov sp,itmp1 /* remove stackframe info */
521 mov itmp1,0*4(sp) /* stackframeinfo pointer */
522 call stacktrace_remove_stackframeinfo
524 mov 1*4(sp),itmp3 /* restore return value */
525 test itmp3,itmp3 /* exception thrown? */
526 jz L_asm_wrapper_patcher_exception
528 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
529 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
530 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
531 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
533 ret /* call new patched code */
535 L_asm_wrapper_patcher_exception:
536 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
538 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
539 call builtin_asm_get_exceptionptrptr
542 lea _exceptionptr,itmp2
544 mov (itmp2),xptr /* get the exception pointer */
545 movl $0,(itmp2) /* clear the exception pointer */
547 pop xpc /* get and remove return address */
548 jmp L_asm_handle_exception
551 /* asm_replacement_out *********************************************************
553 This code is jumped to from the replacement-out stubs that are executed
554 when a thread reaches an activated replacement point.
556 The purpose of asm_replacement_out is to read out the parts of the
557 execution state that cannot be accessed from C code, store this state,
558 and then call the C function replace_me.
561 4 start of stack inside method to replace
562 0 rplpoint * info on the replacement point that was reached
564 *******************************************************************************/
566 /* some room to accomodate changes of the stack frame size during replacement */
567 /* XXX we should find a cleaner solution here */
568 #define REPLACEMENT_ROOM 512
571 /* create stack frame */
572 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
574 /* save registers in execution state */
575 mov %eax,(EAX*8+offes_intregs)(sp)
576 mov %ebx,(EBX*8+offes_intregs)(sp)
577 mov %ecx,(ECX*8+offes_intregs)(sp)
578 mov %edx,(EDX*8+offes_intregs)(sp)
579 mov %esi,(ESI*8+offes_intregs)(sp)
580 mov %edi,(EDI*8+offes_intregs)(sp)
581 mov %ebp,(EBP*8+offes_intregs)(sp)
582 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
585 /* clear high 32bit */
586 movl $0,(4+0*8+offes_intregs)(sp)
587 movl $0,(4+1*8+offes_intregs)(sp)
588 movl $0,(4+2*8+offes_intregs)(sp)
589 movl $0,(4+3*8+offes_intregs)(sp)
590 movl $0,(4+4*8+offes_intregs)(sp)
591 movl $0,(4+5*8+offes_intregs)(sp)
592 movl $0,(4+6*8+offes_intregs)(sp)
593 movl $0,(4+7*8+offes_intregs)(sp)
596 /* calculate sp of method */
598 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
599 mov itmp1,(offes_sp)(sp)
601 /* pv must be looked up via AVL tree */
602 movl $0,(offes_pv)(sp)
604 /* call replace_me */
605 mov -4(itmp1),itmp1 /* rplpoint * */
606 push sp /* arg1: execution state */
607 push itmp1 /* arg0: replacement point */
608 call replace_me /* call C function replace_me */
609 call abort /* NEVER REACHED */
611 /* asm_replacement_in **********************************************************
613 This code writes the given execution state and jumps to the replacement
616 This function never returns!
619 void asm_replacement_in(executionstate *es);
621 *******************************************************************************/
624 mov 4(sp),%ebp /* executionstate *es */
627 mov (offes_sp)(%ebp),%esp
629 /* store address of new code */
630 push (offes_pc)(%ebp)
632 /* copy registers from execution state */
633 mov (EAX*8+offes_intregs)(%ebp),%eax
634 mov (EBX*8+offes_intregs)(%ebp),%ebx
635 mov (ECX*8+offes_intregs)(%ebp),%ecx
636 mov (EDX*8+offes_intregs)(%ebp),%edx
637 mov (ESI*8+offes_intregs)(%ebp),%esi
638 mov (EDI*8+offes_intregs)(%ebp),%edi
640 mov (EBP*8+offes_intregs)(%ebp),%ebp
642 /* jump to new code */
645 /************************ function asm_builtin_x2x *****************************
647 * Wrapper functions for corner cases *
649 *******************************************************************************/
680 /******************* function asm_initialize_thread_stack **********************
682 * initialized a thread stack *
683 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
685 *******************************************************************************/
687 asm_initialize_thread_stack:
688 mov 8(%esp),%eax /* (to)->stackEnd */
689 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
701 mov 4(%esp),%edx /* save (u1*) (func) */
704 ret /* return restorepoint in %eax */
707 /******************* function asm_perform_threadswitch *************************
709 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
711 * performs a threadswitch *
713 *******************************************************************************/
715 asm_perform_threadswitch:
727 mov 36(%esp),%eax /* save current return address */
730 mov 40(%esp),%eax /* first argument **from */
733 mov 48(%esp),%eax /* third argument **stackTop */
736 mov 44(%esp),%eax /* second argument **to */
737 mov 0(%eax),%esp /* load new stack pointer */
743 /* skip stack pointer */
748 add $32,%esp /* leave return address on stack */
752 /********************* function asm_switchstackandcall *************************
754 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
757 * Switches to a new stack, calls a function and switches back. *
758 * a0 new stack pointer *
759 * a1 function pointer *
760 * a2 pointer to variable where stack top should be stored *
761 * a3 pointer to user data, is passed to the function *
763 *******************************************************************************/
765 asm_switchstackandcall:
766 mov 4(%esp),%edx /* first argument *stack */
767 sub $8,%edx /* allocate new stack */
769 mov (%esp),%eax /* save return address on new stack */
772 mov %esp,4(%edx) /* save old stack pointer on new stack */
774 mov 12(%esp),%eax /* third argument **stacktopsave */
775 mov %esp,(%eax) /* save old stack pointer to variable */
777 mov 8(%esp),%eax /* load function pointer */
778 mov 16(%esp),%ecx /* fourth argument *p */
780 mov %edx,%esp /* switch to new stack */
783 mov %ecx,0(%esp) /* pass pointer */
784 call *%eax /* and call function */
787 mov (%esp),%edx /* load return address */
788 mov 4(%esp),%esp /* switch to old stack */
793 asm_getclassvalues_atomic:
795 mov 4(%esp),%ecx /* super */
796 mov 8(%esp),%edx /* sub */
798 mov offbaseval(%ecx),%eax
799 mov offdiffval(%ecx),%ecx
800 mov offbaseval(%edx),%edx
803 mov 16(%esp),%ebx /* out */
804 mov %eax,offcast_super_baseval(%ebx)
805 mov %ecx,offcast_super_diffval(%ebx)
806 mov %edx,offcast_sub_baseval(%ebx)
812 asm_criticalsections:
813 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
826 /* Disable exec-stacks, required for Gentoo ***********************************/
828 #if defined(__GCC__) && defined(__ELF__)
829 .section .note.GNU-stack,"",@progbits
834 * These are local overrides for various environment variables in Emacs.
835 * Please do not remove this and leave it at the end of the file, where
836 * Emacs will automagically detect them.
837 * ---------------------------------------------------------------------
840 * indent-tabs-mode: t
844 * vim:noexpandtab:sw=4:ts=4: