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 4613 2006-03-15 12:04:05Z 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"
46 #include "vm/jit/methodheader.h"
52 /* exported functions and variables *******************************************/
56 .globl asm_vm_call_method
57 .globl asm_vm_call_method_int
58 .globl asm_vm_call_method_long
59 .globl asm_vm_call_method_float
60 .globl asm_vm_call_method_double
62 .globl asm_call_jit_compiler
63 .globl asm_handle_nat_exception
64 .globl asm_handle_exception
66 .globl asm_wrapper_patcher
67 .globl asm_replacement_out
69 .globl asm_builtin_f2i
70 .globl asm_builtin_f2l
71 .globl asm_builtin_d2i
72 .globl asm_builtin_d2l
74 .globl asm_perform_threadswitch
75 .globl asm_initialize_thread_stack
76 .globl asm_switchstackandcall
77 .globl asm_criticalsections
78 .globl asm_getclassvalues_atomic
81 /* asm_md_init *****************************************************************
83 Initialize machine dependent stuff.
85 See: http://www.srware.com/linux_numerics.txt
87 This puts the X86 FPU in 64-bit precision mode. The default under
88 Linux is to use 80-bit mode, which produces subtle differences from
89 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
90 64-bit mode, 299 in 80-bit mode.
92 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
94 *******************************************************************************/
97 sub $4,sp /* allocate space for the FPU state */
98 fnstcw (sp) /* get the FPU state */
100 and $0xfcff,%ax /* remove the extended mode flag */
101 or $0x0200,%ax /* put the double mode flag */
102 mov %eax,(sp) /* store new FPU state */
103 fldcw (sp) /* setup new FPU state */
108 /********************* function asm_calljavafunction ***************************
110 * This function calls a Java-method (which possibly needs compilation) *
111 * with up to 4 address parameters. *
113 * This functions calls the JIT-compiler which eventually translates the *
114 * method into machine code. *
117 * javaobject_header *asm_vm_call_method(methodinfo *m, *
118 * u4 count, u4 size, void *callblock); *
120 *******************************************************************************/
124 .long 0 /* catch type all */
125 .long calljava_xhandler2 /* handler pc */
126 .long calljava_xhandler2 /* end pc */
127 .long L_asm_vm_call_method /* start pc */
128 .long 1 /* extable size */
129 .long 0 /* line number table start */
130 .long 0 /* line number table size */
131 .long 0 /* fltsave */
132 .long 0 /* intsave */
135 .long 0 /* frame size */
136 .long 0 /* method pointer (pointer to name) */
139 asm_vm_call_method_int:
140 asm_vm_call_method_long:
141 asm_vm_call_method_float:
142 asm_vm_call_method_double:
143 L_asm_vm_call_method: /* required for PIC code */
145 mov %esp,%ebp /* save stackptr */
147 push %ebx /* save registers */
151 mov 4*4(%ebp),%eax /* pointer to arg block (4(push)+4(return)+4+4)*/
152 mov 3*4(%ebp),%ecx /* arg count (4(push)+4(return)+4 */
154 xor %esi,%esi /* clear stackframe size (MUST be */
155 /* before args check, may be zero!!!) */
156 test %ecx,%ecx /* maybe we have no args */
157 jle calljava_copydone
159 mov %ecx,%edx /* calculate stack size */
160 mov %eax,%edi /* save pointer to arg block */
162 calljava_calcstacksize:
163 mov offvmargtype(%eax),%ebx
164 test $1,%ebx /* two word type? */
165 jz calljava_onewordtype
166 add $4,%esi /* add 1 slot to stackframe size */
168 calljava_onewordtype:
169 add $4,%esi /* add 1 slot to stackframe size */
171 test %edx,%edx /* any args left? */
173 add $sizevmarg,%eax /* goto next argument block */
174 jmp calljava_calcstacksize
177 mov %edi,%eax /* restore pointer to arg block */
178 sub %esi,%esp /* create stackframe for arguments */
179 mov %esp,%edi /* move stackpointer into temp variable */
182 mov offvmargdata(%eax),%edx /* copy 4 Byte of Argument */
184 add $4,%edi /* increase sp to next argument */
185 mov offvmargtype(%eax),%ebx /* type -> ebx */
186 test $1,%ebx /* two word type? */
189 mov offvmargdata+4(%eax),%edx /* copy upper 4 byte of 2 word type */
191 add $4,%edi /* increase sp to next argument */
194 sub $1,%ecx /* are there any args left? */
196 jle calljava_copydone
198 add $sizevmarg,%eax /* goto next argument block */
199 jmp calljava_copyloop
202 mov 2*4(%ebp),itmp1 /* move function pointer to itmp1 */
204 lea L_asm_call_jit_compiler,itmp3
205 call *itmp3 /* call JIT compiler */
207 L_asm_vm_call_method_return:
208 add %esi,%esp /* remove arg stack frame */
209 pop %edi /* restore registers */
216 push xptr /* pass exception pointer */
217 call builtin_throw_exception
219 xor v0,v0 /* return NULL */
220 jmp L_asm_vm_call_method_return
223 /* asm_call_jit_compiler *******************************************************
225 Invokes the compiler for untranslated JavaVM methods.
227 Register R0 contains a pointer to the method info structure (prepared
228 by createcompilerstub). Using the return address in R26 and the
229 offset in the LDA instruction or using the value in methodptr R28 the
230 patching address for storing the method address can be computed:
232 Method address was either loaded using
234 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
235 i386_call_reg(REG_ITMP2)
239 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
240 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
241 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
242 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
243 i386_call_reg(REG_ITMP1)
245 In the static case the method pointer can be computed using the
246 return address and the lda function following the jmp instruction.
248 *******************************************************************************/
250 asm_call_jit_compiler:
251 L_asm_call_jit_compiler: /* required for PIC code */
252 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
253 mov itmp1,(4+0)*4(sp) /* save method pointer */
255 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
256 mov -1(itmp3),itmp1b /* get function code */
257 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
258 jne L_not_static_special
260 sub $6,itmp3 /* calculate address of immediate */
261 jmp L_call_jit_compile
263 L_not_static_special:
264 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
265 jne L_not_virtual_interface
267 sub $6,itmp3 /* calculate address of offset */
268 mov (itmp3),itmp3 /* get offset */
269 add itmp2,itmp3 /* add base address to get method adr */
270 jmp L_call_jit_compile
272 L_not_virtual_interface:
273 xor itmp3,itmp3 /* a call from asm_calljavafunction */
276 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
278 mov sp,itmp1 /* create stackframe info */
280 mov itmp1,0*4(sp) /* stackframeinfo pointer */
281 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
283 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
285 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
287 call stacktrace_create_inline_stackframeinfo
289 mov (4+0)*4(sp),itmp1 /* pass method pointer */
292 mov v0,(4+0)*4(sp) /* save return value */
294 mov sp,itmp1 /* remove stackframe info */
296 mov itmp1,0*4(sp) /* stackframeinfo pointer */
297 call stacktrace_remove_stackframeinfo
299 mov (4+0)*4(sp),v0 /* restore return value */
300 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
302 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
304 test v0,v0 /* check for exception */
305 je L_asm_call_jit_compiler_exception
307 test itmp3,itmp3 /* was this a JIT call? */
310 mov v0,(itmp3) /* save the new method pointer */
313 jmp *v0 /* ...and now call the new method */
315 L_asm_call_jit_compiler_exception:
316 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
317 call builtin_asm_get_exceptionptrptr
318 mov v0,itmp2 /* v0 == itmp1 */
320 lea _exceptionptr,itmp2
322 mov (itmp2),xptr /* get the exception pointer */
323 movl $0,(itmp2) /* clear the exception pointer */
325 pop xpc /* get return address */
326 sub $2,xpc /* faulting address is ra - 2 */
327 jmp L_asm_handle_exception
330 /* asm_handle_exception ********************************************************
332 * This function handles an exception. It does not use the usual calling *
333 * conventions. The exception pointer is passed in REG_ITMP1 and the *
334 * pc from the exception raising position is passed in REG_ITMP2. It searches *
335 * the local exception table for a handler. If no one is found, it unwinds *
336 * stacks and continues searching the callers. *
338 *******************************************************************************/
340 asm_handle_nat_exception:
341 add $4,sp /* clear return address of native stub*/
343 asm_handle_exception:
344 L_asm_handle_exception: /* required for PIC code */
345 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
347 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
348 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
350 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
351 mov $1,t0 /* set maybe-leaf flag */
353 L_asm_handle_exception_stack_loop:
354 sub $(10*4),sp /* create stackframe */
355 mov xptr,4*4(sp) /* save exception pointer */
356 mov xpc,5*4(sp) /* save exception pc */
357 add sp,itmp3 /* calculate Java sp into a3... */
359 mov itmp3,7*4(sp) /* ...and save it */
360 mov t0,8*4(sp) /* save maybe-leaf flag */
362 mov xpc,0*4(sp) /* pass exception pc */
363 call codegen_findmethod
364 mov v0,6*4(sp) /* save data segment pointer */
366 mov 4*4(sp),itmp3 /* pass exception pointer */
368 mov 5*4(sp),itmp3 /* pass exception pc */
370 mov v0,2*4(sp) /* pass data segment pointer */
371 mov 7*4(sp),itmp3 /* pass Java stack pointer */
373 call exceptions_handle_exception
376 jz L_asm_handle_exception_not_catched
378 mov v0,xpc /* move handlerpc into xpc */
379 mov 4*4(sp),xptr /* restore exception pointer */
380 mov 8*4(sp),t0 /* get maybe-leaf flag */
381 add $(10*4),sp /* free stackframe */
383 test t0,t0 /* test for maybe-leaf flag */
384 jz L_asm_handle_exception_no_leaf
386 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
387 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
389 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
391 L_asm_handle_exception_no_leaf:
392 jmp *xpc /* jump to exception handler */
394 L_asm_handle_exception_not_catched:
395 mov 4*4(sp),xptr /* restore exception pointer */
396 mov 6*4(sp),itmp3 /* restore data segment pointer */
397 mov 8*4(sp),t0 /* get maybe-leaf flag */
398 add $(10*4),sp /* free stackframe */
401 jz L_asm_handle_exception_no_leaf_stack
403 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
404 xor t0,t0 /* clear the maybe-leaf flag */
406 L_asm_handle_exception_no_leaf_stack:
407 mov FrameSize(itmp3),itmp2 /* get frame size */
408 add sp,itmp2 /* pointer to save area */
410 push xptr /* we are out of registers */
412 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
427 shl $2,itmp1 /* multiply by 4 bytes */
432 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
457 pop xptr /* restore exception pointer */
458 mov FrameSize(itmp3),itmp2 /* get frame size */
459 add itmp2,sp /* unwind stack */
461 pop xpc /* the new xpc is return address */
462 sub $2,xpc /* subtract 2-bytes for call */
464 xor itmp3,itmp3 /* prepare a3 for handle_exception */
466 jmp L_asm_handle_exception_stack_loop
469 /* asm_wrapper_patcher *********************************************************
476 16 pointer to virtual java_objectheader
477 12 last byte of machine code (xmcode)
478 8 machine code (which is patched back later)
479 4 unresolved field reference
480 0 patcher function pointer to call
482 *******************************************************************************/
485 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
487 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
488 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
490 mov sp,itmp1 /* create stackframe info */
492 mov itmp1,0*4(sp) /* stackframeinfo pointer */
493 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
495 add $((7+2+4)*4+sizestackframeinfo),itmp2
496 mov itmp2,2*4(sp) /* pass Java sp */
497 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
498 mov itmp3,3*4(sp) /* pass ra to java function */
499 call stacktrace_create_inline_stackframeinfo
501 mov sp,itmp1 /* pass stack pointer */
502 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
504 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
505 call *itmp1 /* call the patcher function */
506 mov v0,1*4(sp) /* save return value */
508 mov sp,itmp1 /* remove stackframe info */
510 mov itmp1,0*4(sp) /* stackframeinfo pointer */
511 call stacktrace_remove_stackframeinfo
513 mov 1*4(sp),itmp3 /* restore return value */
514 test itmp3,itmp3 /* exception thrown? */
515 jz L_asm_wrapper_patcher_exception
517 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
518 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
519 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
520 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
522 ret /* call new patched code */
524 L_asm_wrapper_patcher_exception:
525 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
527 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
528 call builtin_asm_get_exceptionptrptr
531 lea _exceptionptr,itmp2
533 mov (itmp2),xptr /* get the exception pointer */
534 movl $0,(itmp2) /* clear the exception pointer */
536 pop xpc /* get and remove return address */
537 jmp L_asm_handle_exception
540 /* asm_replacement_out *********************************************************
542 This code is jumped to from the replacement-out stubs that are executed
543 when a thread reaches an activated replacement point.
545 The purpose of asm_replacement_out is to read out the parts of the
546 execution state that cannot be accessed from C code, store this state,
547 and then call the C function replace_me.
550 0 rplpoint * info on the replacement point that was reached
552 *******************************************************************************/
555 sub $(sizeexecutionstate),sp /* create stack frame */
557 mov itmp1,(0*8+offes_regs)(sp)
558 movl $0,(4+0*8+offes_regs)(sp)
559 mov itmp2,(1*8+offes_regs)(sp)
560 movl $0,(4+1*8+offes_regs)(sp)
561 mov itmp3,(2*8+offes_regs)(sp)
562 movl $0,(4+2*8+offes_regs)(sp)
564 mov sizeexecutionstate(sp),itmp1 /* rplpoint * */
565 push sp /* arg1: execution state */
566 push itmp1 /* arg0: replacement point */
567 call replace_me /* call C function replace_me */
568 call abort /* NEVER REACHED */
570 /************************ function asm_builtin_x2x *****************************
572 * Wrapper functions for corner cases *
574 *******************************************************************************/
605 /******************* function asm_initialize_thread_stack **********************
607 * initialized a thread stack *
608 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
610 *******************************************************************************/
612 asm_initialize_thread_stack:
613 mov 8(%esp),%eax /* (to)->stackEnd */
614 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
626 mov 4(%esp),%edx /* save (u1*) (func) */
629 ret /* return restorepoint in %eax */
632 /******************* function asm_perform_threadswitch *************************
634 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
636 * performs a threadswitch *
638 *******************************************************************************/
640 asm_perform_threadswitch:
652 mov 36(%esp),%eax /* save current return address */
655 mov 40(%esp),%eax /* first argument **from */
658 mov 48(%esp),%eax /* third argument **stackTop */
661 mov 44(%esp),%eax /* second argument **to */
662 mov 0(%eax),%esp /* load new stack pointer */
668 /* skip stack pointer */
673 add $32,%esp /* leave return address on stack */
677 /********************* function asm_switchstackandcall *************************
679 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
682 * Switches to a new stack, calls a function and switches back. *
683 * a0 new stack pointer *
684 * a1 function pointer *
685 * a2 pointer to variable where stack top should be stored *
686 * a3 pointer to user data, is passed to the function *
688 *******************************************************************************/
690 asm_switchstackandcall:
691 mov 4(%esp),%edx /* first argument *stack */
692 sub $8,%edx /* allocate new stack */
694 mov (%esp),%eax /* save return address on new stack */
697 mov %esp,4(%edx) /* save old stack pointer on new stack */
699 mov 12(%esp),%eax /* third argument **stacktopsave */
700 mov %esp,(%eax) /* save old stack pointer to variable */
702 mov 8(%esp),%eax /* load function pointer */
703 mov 16(%esp),%ecx /* fourth argument *p */
705 mov %edx,%esp /* switch to new stack */
708 mov %ecx,0(%esp) /* pass pointer */
709 call *%eax /* and call function */
712 mov (%esp),%edx /* load return address */
713 mov 4(%esp),%esp /* switch to old stack */
718 asm_getclassvalues_atomic:
720 mov 4(%esp),%ecx /* super */
721 mov 8(%esp),%edx /* sub */
723 mov offbaseval(%ecx),%eax
724 mov offdiffval(%ecx),%ecx
725 mov offbaseval(%edx),%edx
728 mov 16(%esp),%ebx /* out */
729 mov %eax,offcast_super_baseval(%ebx)
730 mov %ecx,offcast_super_diffval(%ebx)
731 mov %edx,offcast_sub_baseval(%ebx)
737 asm_criticalsections:
738 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
751 /* Disable exec-stacks, required for Gentoo ***********************************/
753 #if defined(__GCC__) && defined(__ELF__)
754 .section .note.GNU-stack,"",@progbits
759 * These are local overrides for various environment variables in Emacs.
760 * Please do not remove this and leave it at the end of the file, where
761 * Emacs will automagically detect them.
762 * ---------------------------------------------------------------------
765 * indent-tabs-mode: t
769 * vim:noexpandtab:sw=4:ts=4: