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 4392 2006-01-31 15:35:22Z 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 .globl asm_calljavafunction_int
58 .globl asm_calljavafunction2
59 .globl asm_calljavafunction2int
60 .globl asm_calljavafunction2long
61 .globl asm_calljavafunction2float
62 .globl asm_calljavafunction2double
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_builtin_f2i
71 .globl asm_builtin_f2l
72 .globl asm_builtin_d2i
73 .globl asm_builtin_d2l
75 .globl asm_perform_threadswitch
76 .globl asm_initialize_thread_stack
77 .globl asm_switchstackandcall
78 .globl asm_criticalsections
79 .globl asm_getclassvalues_atomic
82 /* asm_md_init *****************************************************************
84 Initialize machine dependent stuff.
86 See: http://www.srware.com/linux_numerics.txt
88 This puts the X86 FPU in 64-bit precision mode. The default under
89 Linux is to use 80-bit mode, which produces subtle differences from
90 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
91 64-bit mode, 299 in 80-bit mode.
93 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
95 *******************************************************************************/
98 sub $4,sp /* allocate space for the FPU state */
99 fnstcw (sp) /* get the FPU state */
101 and $0xfcff,%ax /* remove the extended mode flag */
102 or $0x0200,%ax /* put the double mode flag */
103 mov %eax,(sp) /* store new FPU state */
104 fldcw (sp) /* setup new FPU state */
109 /********************* function asm_calljavafunction ***************************
111 * This function calls a Java-method (which possibly needs compilation) *
112 * with up to 4 address parameters. *
114 * This functions calls the JIT-compiler which eventually translates the *
115 * method into machine code. *
118 * javaobject_header *asm_calljavamethod (methodinfo *m, *
119 * void *arg1, void *arg2, void *arg3, void *arg4); *
121 *******************************************************************************/
125 .long 0 /* catch type all */
126 .long calljava_xhandler /* handler pc */
127 .long calljava_xhandler /* end pc */
128 .long asm_calljavafunction /* start pc */
129 .long 1 /* extable size */
130 .long 0 /* line number table start */
131 .long 0 /* line number table size */
132 .long 0 /* fltsave */
133 .long 0 /* intsave */
136 .long 0 /* frame size */
137 .long 0 /* method pointer (pointer to name) */
139 asm_calljavafunction:
140 asm_calljavafunction_int:
141 push bp /* allocate stack space */
144 push %ebx /* save registers */
148 sub $(4*4),sp /* 4 adress parameters * 4 Bytes */
149 mov 5*4(bp),itmp1 /* copy adress parameters to new block*/
161 mov 2*4(bp),itmp1 /* move function pointer to %eax */
163 lea asm_call_jit_compiler,itmp3
164 call *itmp3 /* call JIT compiler */
166 L_asm_calljavafunction_return:
168 pop %edi /* restore registers */
175 push xptr /* pass exception pointer */
176 call builtin_throw_exception
178 xor v0,v0 /* return NULL */
179 jmp L_asm_calljavafunction_return
182 /********************* function asm_calljavafunction ***************************
184 * This function calls a Java-method (which possibly needs compilation) *
185 * with up to 4 address parameters. *
187 * This functions calls the JIT-compiler which eventually translates the *
188 * method into machine code. *
191 * javaobject_header *asm_calljavafunction2(methodinfo *m, *
192 * u4 count, u4 size, void *callblock); *
194 *******************************************************************************/
198 .long 0 /* catch type all */
199 .long calljava_xhandler2 /* handler pc */
200 .long calljava_xhandler2 /* end pc */
201 .long asm_calljavafunction2 /* start pc */
202 .long 1 /* extable size */
203 .long 0 /* line number table start */
204 .long 0 /* line number table size */
205 .long 0 /* fltsave */
206 .long 0 /* intsave */
209 .long 0 /* frame size */
210 .long 0 /* method pointer (pointer to name) */
212 asm_calljavafunction2:
213 asm_calljavafunction2int:
214 asm_calljavafunction2long:
215 asm_calljavafunction2float:
216 asm_calljavafunction2double:
218 mov %esp,%ebp /* save stackptr */
220 push %ebx /* save registers */
224 mov 20(%ebp),%eax /* pointer to arg block (4(push)+4(return)+4+4+4)*/
225 mov 12(%ebp),%ecx /* arg count (4(push)+4(return)+4 */
227 xor %esi,%esi /* clear stackframe size (MUST be */
228 /* before args check, may be zero!!!) */
229 test %ecx,%ecx /* maybe we have no args */
230 jle calljava_copydone
232 mov %ecx,%edx /* calculate stack size */
233 mov %eax,%edi /* save pointer to arg block */
235 calljava_calcstacksize:
236 mov offjniitemtype(%eax),%ebx
237 test $1,%ebx /* two word type? */
238 jz calljava_onewordtype
239 add $4,%esi /* add 1 slot to stackframe size */
241 calljava_onewordtype:
242 add $4,%esi /* add 1 slot to stackframe size */
244 test %edx,%edx /* any args left? */
246 add $sizejniblock,%eax /* goto next argument block */
247 jmp calljava_calcstacksize
250 mov %edi,%eax /* restore pointer to arg block */
251 sub %esi,%esp /* create stackframe for arguments */
252 mov %esp,%edi /* move stackpointer into temp variable */
255 mov offjniitem(%eax),%edx /* copy 4 Byte of Argument */
257 add $4,%edi /* increase sp to next argument */
258 mov offjniitemtype(%eax),%ebx /* type -> ebx */
259 test $1,%ebx /* Two Word Type? */
262 mov offjniitem+4(%eax),%edx /* copy upper 4 Byte of 2 Word Type */
264 add $4,%edi /* increase sp to next argument */
267 sub $1,%ecx /* are there any args left? */
269 jle calljava_copydone
271 add $sizejniblock,%eax /* goto next argument block */
272 jmp calljava_copyloop
275 mov 8(%ebp),%eax /* move function pointer to %eax */
277 lea asm_call_jit_compiler,itmp3
278 call *itmp3 /* call JIT compiler */
280 L_asm_calljavafunction2_return:
281 add %esi,%esp /* remove arg stack frame */
282 pop %edi /* restore registers */
289 push xptr /* pass exception pointer */
290 call builtin_throw_exception
292 xor v0,v0 /* return NULL */
293 jmp L_asm_calljavafunction2_return
296 /****************** function asm_call_jit_compiler *****************************
298 * invokes the compiler for untranslated JavaVM methods. *
300 * Register R0 contains a pointer to the method info structure (prepared *
301 * by createcompilerstub). Using the return address in R26 and the *
302 * offset in the LDA instruction or using the value in methodptr R28 the *
303 * patching address for storing the method address can be computed: *
305 * method address was either loaded using *
307 * i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special *
308 * i386_call_reg(REG_ITMP2) *
312 * i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface *
313 * i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2) *
314 * i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \ *
315 * sizeof(methodptr) * m->vftblindex, REG_ITMP1) *
316 * i386_call_reg(REG_ITMP1) *
318 * in the static case the method pointer can be computed using the *
319 * return address and the lda function following the jmp instruction *
321 *******************************************************************************/
323 asm_call_jit_compiler:
324 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
325 mov itmp1,(4+0)*4(sp) /* save method pointer */
327 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
328 mov -1(itmp3),itmp1b /* get function code */
329 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
330 jne L_not_static_special
332 sub $6,itmp3 /* calculate address of immediate */
333 jmp L_call_jit_compile
335 L_not_static_special:
336 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
337 jne L_not_virtual_interface
339 sub $6,itmp3 /* calculate address of offset */
340 mov (itmp3),itmp3 /* get offset */
341 add itmp2,itmp3 /* add base address to get method adr */
342 jmp L_call_jit_compile
344 L_not_virtual_interface:
345 xor itmp3,itmp3 /* a call from asm_calljavafunction */
348 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
350 mov sp,itmp1 /* create stackframe info */
352 mov itmp1,0*4(sp) /* stackframeinfo pointer */
353 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
355 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
357 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
359 call stacktrace_create_inline_stackframeinfo
361 mov (4+0)*4(sp),itmp1 /* pass method pointer */
364 mov v0,(4+0)*4(sp) /* save return value */
366 mov sp,itmp1 /* remove stackframe info */
368 mov itmp1,0*4(sp) /* stackframeinfo pointer */
369 call stacktrace_remove_stackframeinfo
371 mov (4+0)*4(sp),v0 /* restore return value */
372 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
374 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
376 test v0,v0 /* check for exception */
377 je L_asm_call_jit_compiler_exception
379 test itmp3,itmp3 /* was this a JIT call? */
382 mov v0,(itmp3) /* save the new method pointer */
385 jmp *v0 /* ...and now call the new method */
387 L_asm_call_jit_compiler_exception:
388 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
389 call builtin_asm_get_exceptionptrptr
390 mov v0,itmp2 /* v0 == itmp1 */
392 lea _exceptionptr,itmp2
394 mov (itmp2),xptr /* get the exception pointer */
395 movl $0,(itmp2) /* clear the exception pointer */
397 pop xpc /* get return address */
398 sub $2,xpc /* faulting address is ra - 2 */
399 jmp asm_handle_exception
402 /* asm_handle_exception ********************************************************
404 * This function handles an exception. It does not use the usual calling *
405 * conventions. The exception pointer is passed in REG_ITMP1 and the *
406 * pc from the exception raising position is passed in REG_ITMP2. It searches *
407 * the local exception table for a handler. If no one is found, it unwinds *
408 * stacks and continues searching the callers. *
410 *******************************************************************************/
412 asm_handle_nat_exception:
413 add $4,sp /* clear return address of native stub*/
415 asm_handle_exception:
416 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
418 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
419 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
421 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
422 mov $1,t0 /* set maybe-leaf flag */
424 L_asm_handle_exception_stack_loop:
425 sub $(10*4),sp /* create stackframe */
426 mov xptr,4*4(sp) /* save exception pointer */
427 mov xpc,5*4(sp) /* save exception pc */
428 add sp,itmp3 /* calculate Java sp into a3... */
430 mov itmp3,7*4(sp) /* ...and save it */
431 mov t0,8*4(sp) /* save maybe-leaf flag */
433 mov xpc,0*4(sp) /* pass exception pc */
434 call codegen_findmethod
435 mov v0,6*4(sp) /* save data segment pointer */
437 mov 4*4(sp),itmp3 /* pass exception pointer */
439 mov 5*4(sp),itmp3 /* pass exception pc */
441 mov v0,2*4(sp) /* pass data segment pointer */
442 mov 7*4(sp),itmp3 /* pass Java stack pointer */
444 call exceptions_handle_exception
447 jz L_asm_handle_exception_not_catched
449 mov v0,xpc /* move handlerpc into xpc */
450 mov 4*4(sp),xptr /* restore exception pointer */
451 mov 8*4(sp),t0 /* get maybe-leaf flag */
452 add $(10*4),sp /* free stackframe */
454 test t0,t0 /* test for maybe-leaf flag */
455 jz L_asm_handle_exception_no_leaf
457 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
458 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
460 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
462 L_asm_handle_exception_no_leaf:
463 jmp *xpc /* jump to exception handler */
465 L_asm_handle_exception_not_catched:
466 mov 4*4(sp),xptr /* restore exception pointer */
467 mov 6*4(sp),itmp3 /* restore data segment pointer */
468 mov 8*4(sp),t0 /* get maybe-leaf flag */
469 add $(10*4),sp /* free stackframe */
472 jz L_asm_handle_exception_no_leaf_stack
474 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
475 xor t0,t0 /* clear the maybe-leaf flag */
477 L_asm_handle_exception_no_leaf_stack:
478 mov FrameSize(itmp3),itmp2 /* get frame size */
479 add sp,itmp2 /* pointer to save area */
481 push xptr /* we are out of registers */
483 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
498 shl $2,itmp1 /* multiply by 4 bytes */
503 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
528 pop xptr /* restore exception pointer */
529 mov FrameSize(itmp3),itmp2 /* get frame size */
530 add itmp2,sp /* unwind stack */
532 pop xpc /* the new xpc is return address */
533 sub $2,xpc /* subtract 2-bytes for call */
535 xor itmp3,itmp3 /* prepare a3 for handle_exception */
537 jmp L_asm_handle_exception_stack_loop
540 /* asm_wrapper_patcher *********************************************************
546 16 pointer to virtual java_objectheader
547 12 last byte of machine code (xmcode)
548 8 machine code (which is patched back later)
549 4 unresolved field reference
550 0 patcher function pointer to call
552 *******************************************************************************/
555 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
557 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
558 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
560 mov sp,itmp1 /* create stackframe info */
562 mov itmp1,0*4(sp) /* stackframeinfo pointer */
563 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
565 add $((6+2+4)*4+sizestackframeinfo),itmp2
567 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
569 call stacktrace_create_inline_stackframeinfo
571 mov sp,itmp1 /* pass stack pointer */
572 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
574 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
575 call *itmp1 /* call the patcher function */
576 mov v0,1*4(sp) /* save return value */
578 mov sp,itmp1 /* remove stackframe info */
580 mov itmp1,0*4(sp) /* stackframeinfo pointer */
581 call stacktrace_remove_stackframeinfo
583 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
584 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
585 mov 1*4(sp),itmp3 /* restore return value */
587 add $((5+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
588 test itmp3,itmp3 /* exception thrown? */
589 jz L_asm_wrapper_patcher_exception
590 ret /* call new patched code */
592 L_asm_wrapper_patcher_exception:
593 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
594 call builtin_asm_get_exceptionptrptr
597 lea _exceptionptr,itmp2
599 mov (itmp2),xptr /* get the exception pointer */
600 movl $0,(itmp2) /* clear the exception pointer */
602 pop xpc /* get and remove return address */
603 jmp asm_handle_exception
606 /************************ function asm_builtin_x2x *****************************
608 * Wrapper functions for corner cases *
610 *******************************************************************************/
641 /******************* function asm_initialize_thread_stack **********************
643 * initialized a thread stack *
644 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
646 *******************************************************************************/
648 asm_initialize_thread_stack:
649 mov 8(%esp),%eax /* (to)->stackEnd */
650 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
662 mov 4(%esp),%edx /* save (u1*) (func) */
665 ret /* return restorepoint in %eax */
668 /******************* function asm_perform_threadswitch *************************
670 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
672 * performs a threadswitch *
674 *******************************************************************************/
676 asm_perform_threadswitch:
688 mov 36(%esp),%eax /* save current return address */
691 mov 40(%esp),%eax /* first argument **from */
694 mov 48(%esp),%eax /* third argument **stackTop */
697 mov 44(%esp),%eax /* second argument **to */
698 mov 0(%eax),%esp /* load new stack pointer */
704 /* skip stack pointer */
709 add $32,%esp /* leave return address on stack */
713 /********************* function asm_switchstackandcall *************************
715 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
718 * Switches to a new stack, calls a function and switches back. *
719 * a0 new stack pointer *
720 * a1 function pointer *
721 * a2 pointer to variable where stack top should be stored *
722 * a3 pointer to user data, is passed to the function *
724 *******************************************************************************/
726 asm_switchstackandcall:
727 mov 4(%esp),%edx /* first argument *stack */
728 sub $8,%edx /* allocate new stack */
730 mov (%esp),%eax /* save return address on new stack */
733 mov %esp,4(%edx) /* save old stack pointer on new stack */
735 mov 12(%esp),%eax /* third argument **stacktopsave */
736 mov %esp,(%eax) /* save old stack pointer to variable */
738 mov 8(%esp),%eax /* load function pointer */
739 mov 16(%esp),%ecx /* fourth argument *p */
741 mov %edx,%esp /* switch to new stack */
744 mov %ecx,0(%esp) /* pass pointer */
745 call *%eax /* and call function */
748 mov (%esp),%edx /* load return address */
749 mov 4(%esp),%esp /* switch to old stack */
754 asm_getclassvalues_atomic:
756 mov 4(%esp),%ecx /* super */
757 mov 8(%esp),%edx /* sub */
759 mov offbaseval(%ecx),%eax
760 mov offdiffval(%ecx),%ecx
761 mov offbaseval(%edx),%edx
764 mov 16(%esp),%ebx /* out */
765 mov %eax,offcast_super_baseval(%ebx)
766 mov %ecx,offcast_super_diffval(%ebx)
767 mov %edx,offcast_sub_baseval(%ebx)
773 asm_criticalsections:
774 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
788 * These are local overrides for various environment variables in Emacs.
789 * Please do not remove this and leave it at the end of the file, where
790 * Emacs will automagically detect them.
791 * ---------------------------------------------------------------------
794 * indent-tabs-mode: t