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
33 $Id: asmpart.S 4535 2006-02-21 09:34:01Z twisti $
40 #include "vm/jit/abi.h"
41 #include "vm/jit/i386/md-abi.h"
42 #include "vm/jit/i386/md-asm.h"
43 #include "vm/jit/i386/offsets.h"
45 #include "vm/jit/methodheader.h"
51 /* exported functions and variables *******************************************/
55 .globl asm_calljavafunction
56 .type asm_calljavafunction, @function
58 .globl asm_calljavafunction_int
60 .globl asm_calljavafunction2
61 .globl asm_calljavafunction2int
62 .globl asm_calljavafunction2long
63 .globl asm_calljavafunction2float
64 .globl asm_calljavafunction2double
66 .globl asm_call_jit_compiler
67 .globl asm_handle_nat_exception
68 .globl asm_handle_exception
70 .globl asm_wrapper_patcher
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_calljavamethod (methodinfo *m, *
121 * void *arg1, void *arg2, void *arg3, void *arg4); *
123 *******************************************************************************/
127 .long 0 /* catch type all */
128 .long calljava_xhandler /* handler pc */
129 .long calljava_xhandler /* end pc */
130 .long L_asm_calljavafunction /* 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) */
141 asm_calljavafunction:
142 asm_calljavafunction_int:
143 L_asm_calljavafunction: /* required for PIC code */
144 push bp /* allocate stack space */
147 push %ebx /* save registers */
151 sub $(4*4),sp /* 4 adress parameters * 4 Bytes */
152 mov 5*4(bp),itmp1 /* copy adress parameters to new block*/
164 mov 2*4(bp),itmp1 /* move function pointer to %eax */
166 lea L_asm_call_jit_compiler,itmp3
167 call *itmp3 /* call JIT compiler */
169 L_asm_calljavafunction_return:
171 pop %edi /* restore registers */
178 push xptr /* pass exception pointer */
179 call builtin_throw_exception
181 xor v0,v0 /* return NULL */
182 jmp L_asm_calljavafunction_return
185 /********************* function asm_calljavafunction ***************************
187 * This function calls a Java-method (which possibly needs compilation) *
188 * with up to 4 address parameters. *
190 * This functions calls the JIT-compiler which eventually translates the *
191 * method into machine code. *
194 * javaobject_header *asm_calljavafunction2(methodinfo *m, *
195 * u4 count, u4 size, void *callblock); *
197 *******************************************************************************/
201 .long 0 /* catch type all */
202 .long calljava_xhandler2 /* handler pc */
203 .long calljava_xhandler2 /* end pc */
204 .long L_asm_calljavafunction2 /* start pc */
205 .long 1 /* extable size */
206 .long 0 /* line number table start */
207 .long 0 /* line number table size */
208 .long 0 /* fltsave */
209 .long 0 /* intsave */
212 .long 0 /* frame size */
213 .long 0 /* method pointer (pointer to name) */
215 asm_calljavafunction2:
216 asm_calljavafunction2int:
217 asm_calljavafunction2long:
218 asm_calljavafunction2float:
219 asm_calljavafunction2double:
220 L_asm_calljavafunction2: /* required for PIC code */
222 mov %esp,%ebp /* save stackptr */
224 push %ebx /* save registers */
228 mov 20(%ebp),%eax /* pointer to arg block (4(push)+4(return)+4+4+4)*/
229 mov 12(%ebp),%ecx /* arg count (4(push)+4(return)+4 */
231 xor %esi,%esi /* clear stackframe size (MUST be */
232 /* before args check, may be zero!!!) */
233 test %ecx,%ecx /* maybe we have no args */
234 jle calljava_copydone
236 mov %ecx,%edx /* calculate stack size */
237 mov %eax,%edi /* save pointer to arg block */
239 calljava_calcstacksize:
240 mov offjniitemtype(%eax),%ebx
241 test $1,%ebx /* two word type? */
242 jz calljava_onewordtype
243 add $4,%esi /* add 1 slot to stackframe size */
245 calljava_onewordtype:
246 add $4,%esi /* add 1 slot to stackframe size */
248 test %edx,%edx /* any args left? */
250 add $sizejniblock,%eax /* goto next argument block */
251 jmp calljava_calcstacksize
254 mov %edi,%eax /* restore pointer to arg block */
255 sub %esi,%esp /* create stackframe for arguments */
256 mov %esp,%edi /* move stackpointer into temp variable */
259 mov offjniitem(%eax),%edx /* copy 4 Byte of Argument */
261 add $4,%edi /* increase sp to next argument */
262 mov offjniitemtype(%eax),%ebx /* type -> ebx */
263 test $1,%ebx /* Two Word Type? */
266 mov offjniitem+4(%eax),%edx /* copy upper 4 Byte of 2 Word Type */
268 add $4,%edi /* increase sp to next argument */
271 sub $1,%ecx /* are there any args left? */
273 jle calljava_copydone
275 add $sizejniblock,%eax /* goto next argument block */
276 jmp calljava_copyloop
279 mov 8(%ebp),%eax /* move function pointer to %eax */
281 lea L_asm_call_jit_compiler,itmp3
282 call *itmp3 /* call JIT compiler */
284 L_asm_calljavafunction2_return:
285 add %esi,%esp /* remove arg stack frame */
286 pop %edi /* restore registers */
293 push xptr /* pass exception pointer */
294 call builtin_throw_exception
296 xor v0,v0 /* return NULL */
297 jmp L_asm_calljavafunction2_return
300 /* asm_call_jit_compiler *******************************************************
302 Invokes the compiler for untranslated JavaVM methods.
304 Register R0 contains a pointer to the method info structure (prepared
305 by createcompilerstub). Using the return address in R26 and the
306 offset in the LDA instruction or using the value in methodptr R28 the
307 patching address for storing the method address can be computed:
309 Method address was either loaded using
311 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
312 i386_call_reg(REG_ITMP2)
316 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
317 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
318 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
319 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
320 i386_call_reg(REG_ITMP1)
322 In the static case the method pointer can be computed using the
323 return address and the lda function following the jmp instruction.
325 *******************************************************************************/
327 asm_call_jit_compiler:
328 L_asm_call_jit_compiler: /* required for PIC code */
329 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
330 mov itmp1,(4+0)*4(sp) /* save method pointer */
332 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
333 mov -1(itmp3),itmp1b /* get function code */
334 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
335 jne L_not_static_special
337 sub $6,itmp3 /* calculate address of immediate */
338 jmp L_call_jit_compile
340 L_not_static_special:
341 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
342 jne L_not_virtual_interface
344 sub $6,itmp3 /* calculate address of offset */
345 mov (itmp3),itmp3 /* get offset */
346 add itmp2,itmp3 /* add base address to get method adr */
347 jmp L_call_jit_compile
349 L_not_virtual_interface:
350 xor itmp3,itmp3 /* a call from asm_calljavafunction */
353 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
355 mov sp,itmp1 /* create stackframe info */
357 mov itmp1,0*4(sp) /* stackframeinfo pointer */
358 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
360 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
362 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
364 call stacktrace_create_inline_stackframeinfo
366 mov (4+0)*4(sp),itmp1 /* pass method pointer */
369 mov v0,(4+0)*4(sp) /* save return value */
371 mov sp,itmp1 /* remove stackframe info */
373 mov itmp1,0*4(sp) /* stackframeinfo pointer */
374 call stacktrace_remove_stackframeinfo
376 mov (4+0)*4(sp),v0 /* restore return value */
377 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
379 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
381 test v0,v0 /* check for exception */
382 je L_asm_call_jit_compiler_exception
384 test itmp3,itmp3 /* was this a JIT call? */
387 mov v0,(itmp3) /* save the new method pointer */
390 jmp *v0 /* ...and now call the new method */
392 L_asm_call_jit_compiler_exception:
393 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
394 call builtin_asm_get_exceptionptrptr
395 mov v0,itmp2 /* v0 == itmp1 */
397 lea _exceptionptr,itmp2
399 mov (itmp2),xptr /* get the exception pointer */
400 movl $0,(itmp2) /* clear the exception pointer */
402 pop xpc /* get return address */
403 sub $2,xpc /* faulting address is ra - 2 */
404 jmp L_asm_handle_exception
407 /* asm_handle_exception ********************************************************
409 * This function handles an exception. It does not use the usual calling *
410 * conventions. The exception pointer is passed in REG_ITMP1 and the *
411 * pc from the exception raising position is passed in REG_ITMP2. It searches *
412 * the local exception table for a handler. If no one is found, it unwinds *
413 * stacks and continues searching the callers. *
415 *******************************************************************************/
417 asm_handle_nat_exception:
418 add $4,sp /* clear return address of native stub*/
420 asm_handle_exception:
421 L_asm_handle_exception: /* required for PIC code */
422 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
424 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
425 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
427 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
428 mov $1,t0 /* set maybe-leaf flag */
430 L_asm_handle_exception_stack_loop:
431 sub $(10*4),sp /* create stackframe */
432 mov xptr,4*4(sp) /* save exception pointer */
433 mov xpc,5*4(sp) /* save exception pc */
434 add sp,itmp3 /* calculate Java sp into a3... */
436 mov itmp3,7*4(sp) /* ...and save it */
437 mov t0,8*4(sp) /* save maybe-leaf flag */
439 mov xpc,0*4(sp) /* pass exception pc */
440 call codegen_findmethod
441 mov v0,6*4(sp) /* save data segment pointer */
443 mov 4*4(sp),itmp3 /* pass exception pointer */
445 mov 5*4(sp),itmp3 /* pass exception pc */
447 mov v0,2*4(sp) /* pass data segment pointer */
448 mov 7*4(sp),itmp3 /* pass Java stack pointer */
450 call exceptions_handle_exception
453 jz L_asm_handle_exception_not_catched
455 mov v0,xpc /* move handlerpc into xpc */
456 mov 4*4(sp),xptr /* restore exception pointer */
457 mov 8*4(sp),t0 /* get maybe-leaf flag */
458 add $(10*4),sp /* free stackframe */
460 test t0,t0 /* test for maybe-leaf flag */
461 jz L_asm_handle_exception_no_leaf
463 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
464 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
466 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
468 L_asm_handle_exception_no_leaf:
469 jmp *xpc /* jump to exception handler */
471 L_asm_handle_exception_not_catched:
472 mov 4*4(sp),xptr /* restore exception pointer */
473 mov 6*4(sp),itmp3 /* restore data segment pointer */
474 mov 8*4(sp),t0 /* get maybe-leaf flag */
475 add $(10*4),sp /* free stackframe */
478 jz L_asm_handle_exception_no_leaf_stack
480 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
481 xor t0,t0 /* clear the maybe-leaf flag */
483 L_asm_handle_exception_no_leaf_stack:
484 mov FrameSize(itmp3),itmp2 /* get frame size */
485 add sp,itmp2 /* pointer to save area */
487 push xptr /* we are out of registers */
489 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
504 shl $2,itmp1 /* multiply by 4 bytes */
509 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
534 pop xptr /* restore exception pointer */
535 mov FrameSize(itmp3),itmp2 /* get frame size */
536 add itmp2,sp /* unwind stack */
538 pop xpc /* the new xpc is return address */
539 sub $2,xpc /* subtract 2-bytes for call */
541 xor itmp3,itmp3 /* prepare a3 for handle_exception */
543 jmp L_asm_handle_exception_stack_loop
546 /* asm_wrapper_patcher *********************************************************
552 16 pointer to virtual java_objectheader
553 12 last byte of machine code (xmcode)
554 8 machine code (which is patched back later)
555 4 unresolved field reference
556 0 patcher function pointer to call
558 *******************************************************************************/
561 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
563 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
564 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
566 mov sp,itmp1 /* create stackframe info */
568 mov itmp1,0*4(sp) /* stackframeinfo pointer */
569 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
571 add $((6+2+4)*4+sizestackframeinfo),itmp2
572 mov itmp2,2*4(sp) /* pass Java sp */
573 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
574 mov itmp3,3*4(sp) /* pass ra to java function */
575 call stacktrace_create_inline_stackframeinfo
577 mov sp,itmp1 /* pass stack pointer */
578 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
580 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
581 call *itmp1 /* call the patcher function */
582 mov v0,1*4(sp) /* save return value */
584 mov sp,itmp1 /* remove stackframe info */
586 mov itmp1,0*4(sp) /* stackframeinfo pointer */
587 call stacktrace_remove_stackframeinfo
589 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
590 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
591 mov 1*4(sp),itmp3 /* restore return value */
593 add $((5+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
594 test itmp3,itmp3 /* exception thrown? */
595 jz L_asm_wrapper_patcher_exception
596 ret /* call new patched code */
598 L_asm_wrapper_patcher_exception:
599 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
600 call builtin_asm_get_exceptionptrptr
603 lea _exceptionptr,itmp2
605 mov (itmp2),xptr /* get the exception pointer */
606 movl $0,(itmp2) /* clear the exception pointer */
608 pop xpc /* get and remove return address */
609 jmp L_asm_handle_exception
612 /************************ function asm_builtin_x2x *****************************
614 * Wrapper functions for corner cases *
616 *******************************************************************************/
647 /******************* function asm_initialize_thread_stack **********************
649 * initialized a thread stack *
650 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
652 *******************************************************************************/
654 asm_initialize_thread_stack:
655 mov 8(%esp),%eax /* (to)->stackEnd */
656 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
668 mov 4(%esp),%edx /* save (u1*) (func) */
671 ret /* return restorepoint in %eax */
674 /******************* function asm_perform_threadswitch *************************
676 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
678 * performs a threadswitch *
680 *******************************************************************************/
682 asm_perform_threadswitch:
694 mov 36(%esp),%eax /* save current return address */
697 mov 40(%esp),%eax /* first argument **from */
700 mov 48(%esp),%eax /* third argument **stackTop */
703 mov 44(%esp),%eax /* second argument **to */
704 mov 0(%eax),%esp /* load new stack pointer */
710 /* skip stack pointer */
715 add $32,%esp /* leave return address on stack */
719 /********************* function asm_switchstackandcall *************************
721 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
724 * Switches to a new stack, calls a function and switches back. *
725 * a0 new stack pointer *
726 * a1 function pointer *
727 * a2 pointer to variable where stack top should be stored *
728 * a3 pointer to user data, is passed to the function *
730 *******************************************************************************/
732 asm_switchstackandcall:
733 mov 4(%esp),%edx /* first argument *stack */
734 sub $8,%edx /* allocate new stack */
736 mov (%esp),%eax /* save return address on new stack */
739 mov %esp,4(%edx) /* save old stack pointer on new stack */
741 mov 12(%esp),%eax /* third argument **stacktopsave */
742 mov %esp,(%eax) /* save old stack pointer to variable */
744 mov 8(%esp),%eax /* load function pointer */
745 mov 16(%esp),%ecx /* fourth argument *p */
747 mov %edx,%esp /* switch to new stack */
750 mov %ecx,0(%esp) /* pass pointer */
751 call *%eax /* and call function */
754 mov (%esp),%edx /* load return address */
755 mov 4(%esp),%esp /* switch to old stack */
760 asm_getclassvalues_atomic:
762 mov 4(%esp),%ecx /* super */
763 mov 8(%esp),%edx /* sub */
765 mov offbaseval(%ecx),%eax
766 mov offdiffval(%ecx),%ecx
767 mov offbaseval(%edx),%edx
770 mov 16(%esp),%ebx /* out */
771 mov %eax,offcast_super_baseval(%ebx)
772 mov %ecx,offcast_super_diffval(%ebx)
773 mov %edx,offcast_sub_baseval(%ebx)
779 asm_criticalsections:
780 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
793 /* Disable exec-stacks, required for Gentoo ***********************************/
795 #if defined(__GCC__) && defined(__ELF__)
796 .section .note.GNU-stack,"",@progbits
801 * These are local overrides for various environment variables in Emacs.
802 * Please do not remove this and leave it at the end of the file, where
803 * Emacs will automagically detect them.
804 * ---------------------------------------------------------------------
807 * indent-tabs-mode: t