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 5040 2006-06-19 22:53:53Z twisti $
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_criticalsections
79 .globl asm_getclassvalues_atomic
81 .globl asm_get_cycle_count
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_vm_call_method(methodinfo *m, *
121 * u4 count, u4 size, void *callblock); *
123 *******************************************************************************/
127 .long 0 /* catch type all */
128 .long 0 /* handler pc */
130 .long 0 /* 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 /* codeinfo pointer */
142 asm_vm_call_method_int:
143 asm_vm_call_method_long:
144 asm_vm_call_method_float:
145 asm_vm_call_method_double:
147 mov sp,bp /* save stackptr */
148 sub $(4*4),sp /* create stackframe */
149 and $0xfffffff0,sp /* align stack to 16-byte */
151 mov t0,0*4(sp) /* save registers */
155 mov 4*4(bp),itmp1 /* pointer to arg block (4(push)+4(return)+4+4)*/
156 mov 3*4(bp),itmp2 /* arg count (4(push)+4(return)+4 */
158 mov sp,s1 /* save the stackpointer */
160 test itmp2,itmp2 /* maybe we have no args */
161 jle calljava_copydone
163 mov itmp2,itmp3 /* calculate stack size */
164 mov itmp1,%edi /* save pointer to arg block */
166 calljava_calcstacksize:
167 mov offvmargtype(itmp1),t0
168 test $1,t0 /* two word type? */
169 jz calljava_onewordtype
171 sub $4,sp /* add 1 slot to stackframe size */
173 calljava_onewordtype:
174 sub $4,sp /* add 1 slot to stackframe size */
176 test itmp3,itmp3 /* any args left? */
179 add $sizevmarg,itmp1 /* goto next argument block */
180 jmp calljava_calcstacksize
183 mov %edi,itmp1 /* restore pointer to arg block */
184 and $0xfffffff0,sp /* align stack to 16-byte */
185 mov sp,itmp3 /* initialize pointer for copying */
188 mov offvmargdata(itmp1),t0 /* get 4-bytes of argument */
189 mov t0,(itmp3) /* and store them on the stack */
190 add $4,itmp3 /* increase sp to next argument */
191 mov offvmargtype(itmp1),t0 /* get the argument type */
192 test $1,t0 /* two word type? */
195 mov offvmargdata+4(itmp1),t0 /* get upper 4-bytes of 2 word type */
197 add $4,itmp3 /* increase sp to next argument */
200 sub $1,itmp2 /* are there any args left? */
202 jle calljava_copydone
204 add $sizevmarg,itmp1 /* goto next argument block */
205 jmp calljava_copyloop
208 mov 2*4(bp),itmp1 /* move function pointer to itmp1 */
210 lea L_asm_call_jit_compiler,itmp3
211 call *itmp3 /* call JIT compiler */
213 L_asm_vm_call_method_return:
214 mov s1,sp /* restore stackpointer */
216 mov 0*4(sp),t0 /* restore registers */
223 asm_vm_call_method_exception_handler:
224 push xptr /* pass exception pointer */
225 call builtin_throw_exception
227 jmp L_asm_vm_call_method_return
230 /* asm_call_jit_compiler *******************************************************
232 Invokes the compiler for untranslated JavaVM methods.
234 Register R0 contains a pointer to the method info structure (prepared
235 by createcompilerstub). Using the return address in R26 and the
236 offset in the LDA instruction or using the value in methodptr R28 the
237 patching address for storing the method address can be computed:
239 Method address was either loaded using
241 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
242 i386_call_reg(REG_ITMP2)
246 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
247 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
248 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
249 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
250 i386_call_reg(REG_ITMP1)
252 In the static case the method pointer can be computed using the
253 return address and the lda function following the jmp instruction.
255 *******************************************************************************/
257 asm_call_jit_compiler:
258 L_asm_call_jit_compiler: /* required for PIC code */
259 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
260 mov itmp1,(4+0)*4(sp) /* save method pointer */
262 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
263 mov -1(itmp3),itmp1b /* get function code */
264 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
265 jne L_not_static_special
267 sub $6,itmp3 /* calculate address of immediate */
268 jmp L_call_jit_compile
270 L_not_static_special:
271 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
272 jne L_not_virtual_interface
274 sub $6,itmp3 /* calculate address of offset */
275 mov (itmp3),itmp3 /* get offset */
276 add itmp2,itmp3 /* add base address to get method adr */
277 jmp L_call_jit_compile
279 L_not_virtual_interface:
280 xor itmp3,itmp3 /* a call from asm_calljavafunction */
283 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
285 mov sp,itmp1 /* create stackframe info */
287 mov itmp1,0*4(sp) /* stackframeinfo pointer */
288 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
290 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
292 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
294 call stacktrace_create_inline_stackframeinfo
296 mov (4+0)*4(sp),itmp1 /* pass method pointer */
299 mov v0,(4+0)*4(sp) /* save return value */
301 mov sp,itmp1 /* remove stackframe info */
303 mov itmp1,0*4(sp) /* stackframeinfo pointer */
304 call stacktrace_remove_stackframeinfo
306 mov (4+0)*4(sp),v0 /* restore return value */
307 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
309 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
311 test v0,v0 /* check for exception */
312 je L_asm_call_jit_compiler_exception
314 test itmp3,itmp3 /* was this a JIT call? */
317 mov v0,(itmp3) /* save the new method pointer */
320 jmp *v0 /* ...and now call the new method */
322 L_asm_call_jit_compiler_exception:
323 #if defined(ENABLE_THREADS)
324 call builtin_asm_get_exceptionptrptr
325 mov v0,itmp2 /* v0 == itmp1 */
327 lea _exceptionptr,itmp2
329 mov (itmp2),xptr /* get the exception pointer */
330 movl $0,(itmp2) /* clear the exception pointer */
332 pop xpc /* get return address */
333 sub $2,xpc /* faulting address is ra - 2 */
334 jmp L_asm_handle_exception
337 /* asm_handle_exception ********************************************************
339 * This function handles an exception. It does not use the usual calling *
340 * conventions. The exception pointer is passed in REG_ITMP1 and the *
341 * pc from the exception raising position is passed in REG_ITMP2. It searches *
342 * the local exception table for a handler. If no one is found, it unwinds *
343 * stacks and continues searching the callers. *
345 *******************************************************************************/
347 asm_handle_nat_exception:
348 add $4,sp /* clear return address of native stub*/
350 asm_handle_exception:
351 L_asm_handle_exception: /* required for PIC code */
352 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
354 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
355 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
357 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
358 mov $1,t0 /* set maybe-leaf flag */
360 L_asm_handle_exception_stack_loop:
361 sub $(10*4),sp /* create stackframe */
362 mov xptr,4*4(sp) /* save exception pointer */
363 mov xpc,5*4(sp) /* save exception pc */
364 add sp,itmp3 /* calculate Java sp into a3... */
366 mov itmp3,7*4(sp) /* ...and save it */
367 mov t0,8*4(sp) /* save maybe-leaf flag */
369 mov xpc,0*4(sp) /* pass exception pc */
370 call codegen_findmethod
371 mov v0,6*4(sp) /* save data segment pointer */
373 mov 4*4(sp),itmp3 /* pass exception pointer */
375 mov 5*4(sp),itmp3 /* pass exception pc */
377 mov v0,2*4(sp) /* pass data segment pointer */
378 mov 7*4(sp),itmp3 /* pass Java stack pointer */
380 call exceptions_handle_exception
383 jz L_asm_handle_exception_not_catched
385 mov v0,xpc /* move handlerpc into xpc */
386 mov 4*4(sp),xptr /* restore exception pointer */
387 mov 8*4(sp),t0 /* get maybe-leaf flag */
388 add $(10*4),sp /* free stackframe */
390 test t0,t0 /* test for maybe-leaf flag */
391 jz L_asm_handle_exception_no_leaf
393 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
394 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
396 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
398 L_asm_handle_exception_no_leaf:
399 jmp *xpc /* jump to exception handler */
401 L_asm_handle_exception_not_catched:
402 mov 4*4(sp),xptr /* restore exception pointer */
403 mov 6*4(sp),itmp3 /* restore data segment pointer */
404 mov 8*4(sp),t0 /* get maybe-leaf flag */
405 add $(10*4),sp /* free stackframe */
408 jz L_asm_handle_exception_no_leaf_stack
410 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
411 xor t0,t0 /* clear the maybe-leaf flag */
413 L_asm_handle_exception_no_leaf_stack:
414 mov FrameSize(itmp3),itmp2 /* get frame size */
415 add sp,itmp2 /* pointer to save area */
417 push xptr /* we are out of registers */
419 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
434 shl $2,itmp1 /* multiply by 4 bytes */
439 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
464 pop xptr /* restore exception pointer */
465 mov FrameSize(itmp3),itmp2 /* get frame size */
466 add itmp2,sp /* unwind stack */
468 pop xpc /* the new xpc is return address */
469 sub $2,xpc /* subtract 2-bytes for call */
471 xor itmp3,itmp3 /* prepare a3 for handle_exception */
473 jmp L_asm_handle_exception_stack_loop
476 /* asm_wrapper_patcher *********************************************************
483 16 pointer to virtual java_objectheader
484 12 last byte of machine code (xmcode)
485 8 machine code (which is patched back later)
486 4 unresolved field reference
487 0 patcher function pointer to call
489 *******************************************************************************/
492 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
494 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
495 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
497 mov sp,itmp1 /* create stackframe info */
499 mov itmp1,0*4(sp) /* stackframeinfo pointer */
500 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
502 add $((7+2+4)*4+sizestackframeinfo),itmp2
503 mov itmp2,2*4(sp) /* pass Java sp */
504 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
505 mov itmp3,3*4(sp) /* pass ra to java function */
506 call stacktrace_create_inline_stackframeinfo
508 mov sp,itmp1 /* pass stack pointer */
509 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
511 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
512 call *itmp1 /* call the patcher function */
513 mov v0,1*4(sp) /* save return value */
515 mov sp,itmp1 /* remove stackframe info */
517 mov itmp1,0*4(sp) /* stackframeinfo pointer */
518 call stacktrace_remove_stackframeinfo
520 mov 1*4(sp),itmp3 /* restore return value */
521 test itmp3,itmp3 /* exception thrown? */
522 jz L_asm_wrapper_patcher_exception
524 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
525 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
526 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
527 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
529 ret /* call new patched code */
531 L_asm_wrapper_patcher_exception:
532 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
534 #if defined(ENABLE_THREADS)
535 call builtin_asm_get_exceptionptrptr
538 lea _exceptionptr,itmp2
540 mov (itmp2),xptr /* get the exception pointer */
541 movl $0,(itmp2) /* clear the exception pointer */
543 pop xpc /* get and remove return address */
544 jmp L_asm_handle_exception
547 /* asm_replacement_out *********************************************************
549 This code is jumped to from the replacement-out stubs that are executed
550 when a thread reaches an activated replacement point.
552 The purpose of asm_replacement_out is to read out the parts of the
553 execution state that cannot be accessed from C code, store this state,
554 and then call the C function replace_me.
557 4 start of stack inside method to replace
558 0 rplpoint * info on the replacement point that was reached
560 *******************************************************************************/
562 /* some room to accomodate changes of the stack frame size during replacement */
563 /* XXX we should find a cleaner solution here */
564 #define REPLACEMENT_ROOM 512
567 /* create stack frame */
568 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
570 /* save registers in execution state */
571 mov %eax,(EAX*8+offes_intregs)(sp)
572 mov %ebx,(EBX*8+offes_intregs)(sp)
573 mov %ecx,(ECX*8+offes_intregs)(sp)
574 mov %edx,(EDX*8+offes_intregs)(sp)
575 mov %esi,(ESI*8+offes_intregs)(sp)
576 mov %edi,(EDI*8+offes_intregs)(sp)
577 mov %ebp,(EBP*8+offes_intregs)(sp)
578 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
581 /* clear high 32bit */
582 movl $0,(4+0*8+offes_intregs)(sp)
583 movl $0,(4+1*8+offes_intregs)(sp)
584 movl $0,(4+2*8+offes_intregs)(sp)
585 movl $0,(4+3*8+offes_intregs)(sp)
586 movl $0,(4+4*8+offes_intregs)(sp)
587 movl $0,(4+5*8+offes_intregs)(sp)
588 movl $0,(4+6*8+offes_intregs)(sp)
589 movl $0,(4+7*8+offes_intregs)(sp)
592 /* calculate sp of method */
594 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
595 mov itmp1,(offes_sp)(sp)
597 /* pv must be looked up via AVL tree */
598 movl $0,(offes_pv)(sp)
600 /* call replace_me */
601 mov -4(itmp1),itmp1 /* rplpoint * */
602 push sp /* arg1: execution state */
603 push itmp1 /* arg0: replacement point */
604 call replace_me /* call C function replace_me */
605 call abort /* NEVER REACHED */
607 /* asm_replacement_in **********************************************************
609 This code writes the given execution state and jumps to the replacement
612 This function never returns!
615 void asm_replacement_in(executionstate *es);
617 *******************************************************************************/
620 mov 4(sp),%ebp /* executionstate *es */
623 mov (offes_sp)(%ebp),%esp
625 /* store address of new code */
626 push (offes_pc)(%ebp)
628 /* copy registers from execution state */
629 mov (EAX*8+offes_intregs)(%ebp),%eax
630 mov (EBX*8+offes_intregs)(%ebp),%ebx
631 mov (ECX*8+offes_intregs)(%ebp),%ecx
632 mov (EDX*8+offes_intregs)(%ebp),%edx
633 mov (ESI*8+offes_intregs)(%ebp),%esi
634 mov (EDI*8+offes_intregs)(%ebp),%edi
636 mov (EBP*8+offes_intregs)(%ebp),%ebp
638 /* jump to new code */
641 /************************ function asm_builtin_x2x *****************************
643 * Wrapper functions for corner cases *
645 *******************************************************************************/
676 asm_getclassvalues_atomic:
678 mov 4(%esp),%ecx /* super */
679 mov 8(%esp),%edx /* sub */
681 mov offbaseval(%ecx),%eax
682 mov offdiffval(%ecx),%ecx
683 mov offbaseval(%edx),%edx
686 mov 16(%esp),%ebx /* out */
687 mov %eax,offcast_super_baseval(%ebx)
688 mov %ecx,offcast_super_diffval(%ebx)
689 mov %edx,offcast_sub_baseval(%ebx)
695 asm_criticalsections:
696 #if defined(ENABLE_THREADS)
709 /* Disable exec-stacks, required for Gentoo ***********************************/
711 #if defined(__GCC__) && defined(__ELF__)
712 .section .note.GNU-stack,"",@progbits
716 /* asm_get_cycle_count *********************************************************
718 Get the current time-stamp counter from the CPU.
720 *******************************************************************************/
728 * These are local overrides for various environment variables in Emacs.
729 * Please do not remove this and leave it at the end of the file, where
730 * Emacs will automagically detect them.
731 * ---------------------------------------------------------------------
734 * indent-tabs-mode: t
738 * vim:noexpandtab:sw=4:ts=4: