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 4818 2006-04-24 00:19:06Z edwin $
41 #include "vm/jit/i386/arch.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/abi-asm.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
84 .globl asm_get_cycle_count
87 /* asm_md_init *****************************************************************
89 Initialize machine dependent stuff.
91 See: http://www.srware.com/linux_numerics.txt
93 This puts the X86 FPU in 64-bit precision mode. The default under
94 Linux is to use 80-bit mode, which produces subtle differences from
95 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
96 64-bit mode, 299 in 80-bit mode.
98 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
100 *******************************************************************************/
103 sub $4,sp /* allocate space for the FPU state */
104 fnstcw (sp) /* get the FPU state */
106 and $0xfcff,%ax /* remove the extended mode flag */
107 or $0x0200,%ax /* put the double mode flag */
108 mov %eax,(sp) /* store new FPU state */
109 fldcw (sp) /* setup new FPU state */
114 /********************* function asm_calljavafunction ***************************
116 * This function calls a Java-method (which possibly needs compilation) *
117 * with up to 4 address parameters. *
119 * This functions calls the JIT-compiler which eventually translates the *
120 * method into machine code. *
123 * javaobject_header *asm_vm_call_method(methodinfo *m, *
124 * u4 count, u4 size, void *callblock); *
126 *******************************************************************************/
130 .long 0 /* catch type all */
131 .long 0 /* handler pc */
133 .long 0 /* start pc */
134 .long 1 /* extable size */
135 .long 0 /* line number table start */
136 .long 0 /* line number table size */
137 .long 0 /* fltsave */
138 .long 0 /* intsave */
141 .long 0 /* frame size */
142 .long 0 /* method pointer (pointer to name) */
145 asm_vm_call_method_int:
146 asm_vm_call_method_long:
147 asm_vm_call_method_float:
148 asm_vm_call_method_double:
150 mov sp,bp /* save stackptr */
151 sub $(4*4),sp /* create stackframe */
152 and $0xfffffff0,sp /* align stack to 16-byte */
154 mov t0,0*4(sp) /* save registers */
158 mov 4*4(bp),itmp1 /* pointer to arg block (4(push)+4(return)+4+4)*/
159 mov 3*4(bp),itmp2 /* arg count (4(push)+4(return)+4 */
161 mov sp,s1 /* save the stackpointer */
163 test itmp2,itmp2 /* maybe we have no args */
164 jle calljava_copydone
166 mov itmp2,itmp3 /* calculate stack size */
167 mov itmp1,%edi /* save pointer to arg block */
169 calljava_calcstacksize:
170 mov offvmargtype(itmp1),t0
171 test $1,t0 /* two word type? */
172 jz calljava_onewordtype
174 sub $4,sp /* add 1 slot to stackframe size */
176 calljava_onewordtype:
177 sub $4,sp /* add 1 slot to stackframe size */
179 test itmp3,itmp3 /* any args left? */
182 add $sizevmarg,itmp1 /* goto next argument block */
183 jmp calljava_calcstacksize
186 mov %edi,itmp1 /* restore pointer to arg block */
187 and $0xfffffff0,sp /* align stack to 16-byte */
188 mov sp,itmp3 /* initialize pointer for copying */
191 mov offvmargdata(itmp1),t0 /* get 4-bytes of argument */
192 mov t0,(itmp3) /* and store them on the stack */
193 add $4,itmp3 /* increase sp to next argument */
194 mov offvmargtype(itmp1),t0 /* get the argument type */
195 test $1,t0 /* two word type? */
198 mov offvmargdata+4(itmp1),t0 /* get upper 4-bytes of 2 word type */
200 add $4,itmp3 /* increase sp to next argument */
203 sub $1,itmp2 /* are there any args left? */
205 jle calljava_copydone
207 add $sizevmarg,itmp1 /* goto next argument block */
208 jmp calljava_copyloop
211 mov 2*4(bp),itmp1 /* move function pointer to itmp1 */
213 lea L_asm_call_jit_compiler,itmp3
214 call *itmp3 /* call JIT compiler */
216 L_asm_vm_call_method_return:
217 mov s1,sp /* restore stackpointer */
219 mov 0*4(sp),t0 /* restore registers */
226 asm_vm_call_method_exception_handler:
227 push xptr /* pass exception pointer */
228 call builtin_throw_exception
230 jmp L_asm_vm_call_method_return
233 /* asm_call_jit_compiler *******************************************************
235 Invokes the compiler for untranslated JavaVM methods.
237 Register R0 contains a pointer to the method info structure (prepared
238 by createcompilerstub). Using the return address in R26 and the
239 offset in the LDA instruction or using the value in methodptr R28 the
240 patching address for storing the method address can be computed:
242 Method address was either loaded using
244 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
245 i386_call_reg(REG_ITMP2)
249 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
250 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
251 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
252 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
253 i386_call_reg(REG_ITMP1)
255 In the static case the method pointer can be computed using the
256 return address and the lda function following the jmp instruction.
258 *******************************************************************************/
260 asm_call_jit_compiler:
261 L_asm_call_jit_compiler: /* required for PIC code */
262 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
263 mov itmp1,(4+0)*4(sp) /* save method pointer */
265 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
266 mov -1(itmp3),itmp1b /* get function code */
267 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
268 jne L_not_static_special
270 sub $6,itmp3 /* calculate address of immediate */
271 jmp L_call_jit_compile
273 L_not_static_special:
274 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
275 jne L_not_virtual_interface
277 sub $6,itmp3 /* calculate address of offset */
278 mov (itmp3),itmp3 /* get offset */
279 add itmp2,itmp3 /* add base address to get method adr */
280 jmp L_call_jit_compile
282 L_not_virtual_interface:
283 xor itmp3,itmp3 /* a call from asm_calljavafunction */
286 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
288 mov sp,itmp1 /* create stackframe info */
290 mov itmp1,0*4(sp) /* stackframeinfo pointer */
291 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
293 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
295 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
297 call stacktrace_create_inline_stackframeinfo
299 mov (4+0)*4(sp),itmp1 /* pass method pointer */
302 mov v0,(4+0)*4(sp) /* save return value */
304 mov sp,itmp1 /* remove stackframe info */
306 mov itmp1,0*4(sp) /* stackframeinfo pointer */
307 call stacktrace_remove_stackframeinfo
309 mov (4+0)*4(sp),v0 /* restore return value */
310 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
312 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
314 test v0,v0 /* check for exception */
315 je L_asm_call_jit_compiler_exception
317 test itmp3,itmp3 /* was this a JIT call? */
320 mov v0,(itmp3) /* save the new method pointer */
323 jmp *v0 /* ...and now call the new method */
325 L_asm_call_jit_compiler_exception:
326 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
327 call builtin_asm_get_exceptionptrptr
328 mov v0,itmp2 /* v0 == itmp1 */
330 lea _exceptionptr,itmp2
332 mov (itmp2),xptr /* get the exception pointer */
333 movl $0,(itmp2) /* clear the exception pointer */
335 pop xpc /* get return address */
336 sub $2,xpc /* faulting address is ra - 2 */
337 jmp L_asm_handle_exception
340 /* asm_handle_exception ********************************************************
342 * This function handles an exception. It does not use the usual calling *
343 * conventions. The exception pointer is passed in REG_ITMP1 and the *
344 * pc from the exception raising position is passed in REG_ITMP2. It searches *
345 * the local exception table for a handler. If no one is found, it unwinds *
346 * stacks and continues searching the callers. *
348 *******************************************************************************/
350 asm_handle_nat_exception:
351 add $4,sp /* clear return address of native stub*/
353 asm_handle_exception:
354 L_asm_handle_exception: /* required for PIC code */
355 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
357 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
358 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
360 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
361 mov $1,t0 /* set maybe-leaf flag */
363 L_asm_handle_exception_stack_loop:
364 sub $(10*4),sp /* create stackframe */
365 mov xptr,4*4(sp) /* save exception pointer */
366 mov xpc,5*4(sp) /* save exception pc */
367 add sp,itmp3 /* calculate Java sp into a3... */
369 mov itmp3,7*4(sp) /* ...and save it */
370 mov t0,8*4(sp) /* save maybe-leaf flag */
372 mov xpc,0*4(sp) /* pass exception pc */
373 call codegen_findmethod
374 mov v0,6*4(sp) /* save data segment pointer */
376 mov 4*4(sp),itmp3 /* pass exception pointer */
378 mov 5*4(sp),itmp3 /* pass exception pc */
380 mov v0,2*4(sp) /* pass data segment pointer */
381 mov 7*4(sp),itmp3 /* pass Java stack pointer */
383 call exceptions_handle_exception
386 jz L_asm_handle_exception_not_catched
388 mov v0,xpc /* move handlerpc into xpc */
389 mov 4*4(sp),xptr /* restore exception pointer */
390 mov 8*4(sp),t0 /* get maybe-leaf flag */
391 add $(10*4),sp /* free stackframe */
393 test t0,t0 /* test for maybe-leaf flag */
394 jz L_asm_handle_exception_no_leaf
396 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
397 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
399 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
401 L_asm_handle_exception_no_leaf:
402 jmp *xpc /* jump to exception handler */
404 L_asm_handle_exception_not_catched:
405 mov 4*4(sp),xptr /* restore exception pointer */
406 mov 6*4(sp),itmp3 /* restore data segment pointer */
407 mov 8*4(sp),t0 /* get maybe-leaf flag */
408 add $(10*4),sp /* free stackframe */
411 jz L_asm_handle_exception_no_leaf_stack
413 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
414 xor t0,t0 /* clear the maybe-leaf flag */
416 L_asm_handle_exception_no_leaf_stack:
417 mov FrameSize(itmp3),itmp2 /* get frame size */
418 add sp,itmp2 /* pointer to save area */
420 push xptr /* we are out of registers */
422 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
437 shl $2,itmp1 /* multiply by 4 bytes */
442 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
467 pop xptr /* restore exception pointer */
468 mov FrameSize(itmp3),itmp2 /* get frame size */
469 add itmp2,sp /* unwind stack */
471 pop xpc /* the new xpc is return address */
472 sub $2,xpc /* subtract 2-bytes for call */
474 xor itmp3,itmp3 /* prepare a3 for handle_exception */
476 jmp L_asm_handle_exception_stack_loop
479 /* asm_wrapper_patcher *********************************************************
486 16 pointer to virtual java_objectheader
487 12 last byte of machine code (xmcode)
488 8 machine code (which is patched back later)
489 4 unresolved field reference
490 0 patcher function pointer to call
492 *******************************************************************************/
495 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
497 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
498 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
500 mov sp,itmp1 /* create stackframe info */
502 mov itmp1,0*4(sp) /* stackframeinfo pointer */
503 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
505 add $((7+2+4)*4+sizestackframeinfo),itmp2
506 mov itmp2,2*4(sp) /* pass Java sp */
507 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
508 mov itmp3,3*4(sp) /* pass ra to java function */
509 call stacktrace_create_inline_stackframeinfo
511 mov sp,itmp1 /* pass stack pointer */
512 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
514 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
515 call *itmp1 /* call the patcher function */
516 mov v0,1*4(sp) /* save return value */
518 mov sp,itmp1 /* remove stackframe info */
520 mov itmp1,0*4(sp) /* stackframeinfo pointer */
521 call stacktrace_remove_stackframeinfo
523 mov 1*4(sp),itmp3 /* restore return value */
524 test itmp3,itmp3 /* exception thrown? */
525 jz L_asm_wrapper_patcher_exception
527 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
528 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
529 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
530 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
532 ret /* call new patched code */
534 L_asm_wrapper_patcher_exception:
535 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
537 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
538 call builtin_asm_get_exceptionptrptr
541 lea _exceptionptr,itmp2
543 mov (itmp2),xptr /* get the exception pointer */
544 movl $0,(itmp2) /* clear the exception pointer */
546 pop xpc /* get and remove return address */
547 jmp L_asm_handle_exception
550 /* asm_replacement_out *********************************************************
552 This code is jumped to from the replacement-out stubs that are executed
553 when a thread reaches an activated replacement point.
555 The purpose of asm_replacement_out is to read out the parts of the
556 execution state that cannot be accessed from C code, store this state,
557 and then call the C function replace_me.
560 4 start of stack inside method to replace
561 0 rplpoint * info on the replacement point that was reached
563 *******************************************************************************/
565 /* some room to accomodate changes of the stack frame size during replacement */
566 /* XXX we should find a cleaner solution here */
567 #define REPLACEMENT_ROOM 512
570 /* create stack frame */
571 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
573 /* save registers in execution state */
574 mov %eax,(EAX*8+offes_intregs)(sp)
575 mov %ebx,(EBX*8+offes_intregs)(sp)
576 mov %ecx,(ECX*8+offes_intregs)(sp)
577 mov %edx,(EDX*8+offes_intregs)(sp)
578 mov %esi,(ESI*8+offes_intregs)(sp)
579 mov %edi,(EDI*8+offes_intregs)(sp)
580 mov %ebp,(EBP*8+offes_intregs)(sp)
581 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
584 /* clear high 32bit */
585 movl $0,(4+0*8+offes_intregs)(sp)
586 movl $0,(4+1*8+offes_intregs)(sp)
587 movl $0,(4+2*8+offes_intregs)(sp)
588 movl $0,(4+3*8+offes_intregs)(sp)
589 movl $0,(4+4*8+offes_intregs)(sp)
590 movl $0,(4+5*8+offes_intregs)(sp)
591 movl $0,(4+6*8+offes_intregs)(sp)
592 movl $0,(4+7*8+offes_intregs)(sp)
595 /* calculate sp of method */
597 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
598 mov itmp1,(offes_sp)(sp)
600 /* pv must be looked up via AVL tree */
601 movl $0,(offes_pv)(sp)
603 /* call replace_me */
604 mov -4(itmp1),itmp1 /* rplpoint * */
605 push sp /* arg1: execution state */
606 push itmp1 /* arg0: replacement point */
607 call replace_me /* call C function replace_me */
608 call abort /* NEVER REACHED */
610 /* asm_replacement_in **********************************************************
612 This code writes the given execution state and jumps to the replacement
615 This function never returns!
618 void asm_replacement_in(executionstate *es);
620 *******************************************************************************/
623 mov 4(sp),%ebp /* executionstate *es */
626 mov (offes_sp)(%ebp),%esp
628 /* store address of new code */
629 push (offes_pc)(%ebp)
631 /* copy registers from execution state */
632 mov (EAX*8+offes_intregs)(%ebp),%eax
633 mov (EBX*8+offes_intregs)(%ebp),%ebx
634 mov (ECX*8+offes_intregs)(%ebp),%ecx
635 mov (EDX*8+offes_intregs)(%ebp),%edx
636 mov (ESI*8+offes_intregs)(%ebp),%esi
637 mov (EDI*8+offes_intregs)(%ebp),%edi
639 mov (EBP*8+offes_intregs)(%ebp),%ebp
641 /* jump to new code */
644 /************************ function asm_builtin_x2x *****************************
646 * Wrapper functions for corner cases *
648 *******************************************************************************/
679 /******************* function asm_initialize_thread_stack **********************
681 * initialized a thread stack *
682 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
684 *******************************************************************************/
686 asm_initialize_thread_stack:
687 mov 8(%esp),%eax /* (to)->stackEnd */
688 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
700 mov 4(%esp),%edx /* save (u1*) (func) */
703 ret /* return restorepoint in %eax */
706 /******************* function asm_perform_threadswitch *************************
708 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
710 * performs a threadswitch *
712 *******************************************************************************/
714 asm_perform_threadswitch:
726 mov 36(%esp),%eax /* save current return address */
729 mov 40(%esp),%eax /* first argument **from */
732 mov 48(%esp),%eax /* third argument **stackTop */
735 mov 44(%esp),%eax /* second argument **to */
736 mov 0(%eax),%esp /* load new stack pointer */
742 /* skip stack pointer */
747 add $32,%esp /* leave return address on stack */
751 /********************* function asm_switchstackandcall *************************
753 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
756 * Switches to a new stack, calls a function and switches back. *
757 * a0 new stack pointer *
758 * a1 function pointer *
759 * a2 pointer to variable where stack top should be stored *
760 * a3 pointer to user data, is passed to the function *
762 *******************************************************************************/
764 asm_switchstackandcall:
765 mov 4(%esp),%edx /* first argument *stack */
766 sub $8,%edx /* allocate new stack */
768 mov (%esp),%eax /* save return address on new stack */
771 mov %esp,4(%edx) /* save old stack pointer on new stack */
773 mov 12(%esp),%eax /* third argument **stacktopsave */
774 mov %esp,(%eax) /* save old stack pointer to variable */
776 mov 8(%esp),%eax /* load function pointer */
777 mov 16(%esp),%ecx /* fourth argument *p */
779 mov %edx,%esp /* switch to new stack */
782 mov %ecx,0(%esp) /* pass pointer */
783 call *%eax /* and call function */
786 mov (%esp),%edx /* load return address */
787 mov 4(%esp),%esp /* switch to old stack */
792 asm_getclassvalues_atomic:
794 mov 4(%esp),%ecx /* super */
795 mov 8(%esp),%edx /* sub */
797 mov offbaseval(%ecx),%eax
798 mov offdiffval(%ecx),%ecx
799 mov offbaseval(%edx),%edx
802 mov 16(%esp),%ebx /* out */
803 mov %eax,offcast_super_baseval(%ebx)
804 mov %ecx,offcast_super_diffval(%ebx)
805 mov %edx,offcast_sub_baseval(%ebx)
811 asm_criticalsections:
812 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
825 /* Disable exec-stacks, required for Gentoo ***********************************/
827 #if defined(__GCC__) && defined(__ELF__)
828 .section .note.GNU-stack,"",@progbits
832 /* asm_get_cycle_count *********************************************************
834 Get the current time-stamp counter from the CPU.
836 *******************************************************************************/
844 * These are local overrides for various environment variables in Emacs.
845 * Please do not remove this and leave it at the end of the file, where
846 * Emacs will automagically detect them.
847 * ---------------------------------------------------------------------
850 * indent-tabs-mode: t
854 * vim:noexpandtab:sw=4:ts=4: