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 5054 2006-06-28 19:43:42Z 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_abstractmethoderror
70 .globl asm_wrapper_patcher
72 .globl asm_replacement_out
73 .globl asm_replacement_in
75 .globl asm_builtin_f2i
76 .globl asm_builtin_f2l
77 .globl asm_builtin_d2i
78 .globl asm_builtin_d2l
80 .globl asm_criticalsections
81 .globl asm_getclassvalues_atomic
83 .globl asm_get_cycle_count
86 /* asm_md_init *****************************************************************
88 Initialize machine dependent stuff.
90 See: http://www.srware.com/linux_numerics.txt
92 This puts the X86 FPU in 64-bit precision mode. The default under
93 Linux is to use 80-bit mode, which produces subtle differences from
94 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
95 64-bit mode, 299 in 80-bit mode.
97 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
99 *******************************************************************************/
102 sub $4,sp /* allocate space for the FPU state */
103 fnstcw (sp) /* get the FPU state */
105 and $0xfcff,%ax /* remove the extended mode flag */
106 or $0x0200,%ax /* put the double mode flag */
107 mov %eax,(sp) /* store new FPU state */
108 fldcw (sp) /* setup new FPU state */
113 /********************* function asm_calljavafunction ***************************
115 * This function calls a Java-method (which possibly needs compilation) *
116 * with up to 4 address parameters. *
118 * This functions calls the JIT-compiler which eventually translates the *
119 * method into machine code. *
122 * javaobject_header *asm_vm_call_method(methodinfo *m, *
123 * u4 count, u4 size, void *callblock); *
125 *******************************************************************************/
129 .long 0 /* catch type all */
130 .long 0 /* handler pc */
132 .long 0 /* start pc */
133 .long 1 /* extable size */
134 .long 0 /* line number table start */
135 .long 0 /* line number table size */
136 .long 0 /* fltsave */
137 .long 0 /* intsave */
140 .long 0 /* frame size */
141 .long 0 /* codeinfo pointer */
144 asm_vm_call_method_int:
145 asm_vm_call_method_long:
146 asm_vm_call_method_float:
147 asm_vm_call_method_double:
149 mov sp,bp /* save stackptr */
150 sub $(4*4),sp /* create stackframe */
151 and $0xfffffff0,sp /* align stack to 16-byte */
153 mov t0,0*4(sp) /* save registers */
157 mov 4*4(bp),itmp1 /* pointer to arg block (4(push)+4(return)+4+4)*/
158 mov 3*4(bp),itmp2 /* arg count (4(push)+4(return)+4 */
160 mov sp,s1 /* save the stackpointer */
162 test itmp2,itmp2 /* maybe we have no args */
163 jle calljava_copydone
165 mov itmp2,itmp3 /* calculate stack size */
166 mov itmp1,%edi /* save pointer to arg block */
168 calljava_calcstacksize:
169 mov offvmargtype(itmp1),t0
170 test $1,t0 /* two word type? */
171 jz calljava_onewordtype
173 sub $4,sp /* add 1 slot to stackframe size */
175 calljava_onewordtype:
176 sub $4,sp /* add 1 slot to stackframe size */
178 test itmp3,itmp3 /* any args left? */
181 add $sizevmarg,itmp1 /* goto next argument block */
182 jmp calljava_calcstacksize
185 mov %edi,itmp1 /* restore pointer to arg block */
186 and $0xfffffff0,sp /* align stack to 16-byte */
187 mov sp,itmp3 /* initialize pointer for copying */
190 mov offvmargdata(itmp1),t0 /* get 4-bytes of argument */
191 mov t0,(itmp3) /* and store them on the stack */
192 add $4,itmp3 /* increase sp to next argument */
193 mov offvmargtype(itmp1),t0 /* get the argument type */
194 test $1,t0 /* two word type? */
197 mov offvmargdata+4(itmp1),t0 /* get upper 4-bytes of 2 word type */
199 add $4,itmp3 /* increase sp to next argument */
202 sub $1,itmp2 /* are there any args left? */
204 jle calljava_copydone
206 add $sizevmarg,itmp1 /* goto next argument block */
207 jmp calljava_copyloop
210 mov 2*4(bp),itmp1 /* move function pointer to itmp1 */
212 lea L_asm_call_jit_compiler,itmp3
213 call *itmp3 /* call JIT compiler */
215 L_asm_vm_call_method_return:
216 mov s1,sp /* restore stackpointer */
218 mov 0*4(sp),t0 /* restore registers */
225 asm_vm_call_method_exception_handler:
226 push xptr /* pass exception pointer */
227 call builtin_throw_exception
229 jmp L_asm_vm_call_method_return
232 /* asm_call_jit_compiler *******************************************************
234 Invokes the compiler for untranslated JavaVM methods.
236 Register R0 contains a pointer to the method info structure (prepared
237 by createcompilerstub). Using the return address in R26 and the
238 offset in the LDA instruction or using the value in methodptr R28 the
239 patching address for storing the method address can be computed:
241 Method address was either loaded using
243 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
244 i386_call_reg(REG_ITMP2)
248 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
249 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
250 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
251 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
252 i386_call_reg(REG_ITMP1)
254 In the static case the method pointer can be computed using the
255 return address and the lda function following the jmp instruction.
257 *******************************************************************************/
259 asm_call_jit_compiler:
260 L_asm_call_jit_compiler: /* required for PIC code */
261 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
262 mov itmp1,(4+0)*4(sp) /* save method pointer */
264 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
265 mov -1(itmp3),itmp1b /* get function code */
266 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
267 jne L_not_static_special
269 sub $6,itmp3 /* calculate address of immediate */
270 jmp L_call_jit_compile
272 L_not_static_special:
273 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
274 jne L_not_virtual_interface
276 sub $6,itmp3 /* calculate address of offset */
277 mov (itmp3),itmp3 /* get offset */
278 add itmp2,itmp3 /* add base address to get method adr */
279 jmp L_call_jit_compile
281 L_not_virtual_interface:
282 xor itmp3,itmp3 /* a call from asm_calljavafunction */
285 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
287 mov sp,itmp1 /* create stackframe info */
289 mov itmp1,0*4(sp) /* stackframeinfo pointer */
290 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
292 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
294 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
296 call stacktrace_create_inline_stackframeinfo
298 mov (4+0)*4(sp),itmp1 /* pass method pointer */
301 mov v0,(4+0)*4(sp) /* save return value */
303 mov sp,itmp1 /* remove stackframe info */
305 mov itmp1,0*4(sp) /* stackframeinfo pointer */
306 call stacktrace_remove_stackframeinfo
308 mov (4+0)*4(sp),v0 /* restore return value */
309 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
311 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
313 test v0,v0 /* check for exception */
314 je L_asm_call_jit_compiler_exception
316 test itmp3,itmp3 /* was this a JIT call? */
319 mov v0,(itmp3) /* save the new method pointer */
322 jmp *v0 /* ...and now call the new method */
324 L_asm_call_jit_compiler_exception:
325 #if defined(ENABLE_THREADS)
326 call builtin_asm_get_exceptionptrptr
327 mov v0,itmp2 /* v0 == itmp1 */
329 lea _exceptionptr,itmp2
331 mov (itmp2),xptr /* get the exception pointer */
332 movl $0,(itmp2) /* clear the exception pointer */
334 pop xpc /* get return address */
335 sub $2,xpc /* faulting address is ra - 2 */
336 jmp L_asm_handle_exception
339 /* asm_handle_exception ********************************************************
341 * This function handles an exception. It does not use the usual calling *
342 * conventions. The exception pointer is passed in REG_ITMP1 and the *
343 * pc from the exception raising position is passed in REG_ITMP2. It searches *
344 * the local exception table for a handler. If no one is found, it unwinds *
345 * stacks and continues searching the callers. *
347 *******************************************************************************/
349 asm_handle_nat_exception:
350 add $4,sp /* clear return address of native stub*/
352 asm_handle_exception:
353 L_asm_handle_exception: /* required for PIC code */
354 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
356 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
357 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
359 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
360 mov $1,t0 /* set maybe-leaf flag */
362 L_asm_handle_exception_stack_loop:
363 sub $(10*4),sp /* create stackframe */
364 mov xptr,4*4(sp) /* save exception pointer */
365 mov xpc,5*4(sp) /* save exception pc */
366 add sp,itmp3 /* calculate Java sp into a3... */
368 mov itmp3,7*4(sp) /* ...and save it */
369 mov t0,8*4(sp) /* save maybe-leaf flag */
371 mov xpc,0*4(sp) /* pass exception pc */
372 call codegen_findmethod
373 mov v0,6*4(sp) /* save data segment pointer */
375 mov 4*4(sp),itmp3 /* pass exception pointer */
377 mov 5*4(sp),itmp3 /* pass exception pc */
379 mov v0,2*4(sp) /* pass data segment pointer */
380 mov 7*4(sp),itmp3 /* pass Java stack pointer */
382 call exceptions_handle_exception
385 jz L_asm_handle_exception_not_catched
387 mov v0,xpc /* move handlerpc into xpc */
388 mov 4*4(sp),xptr /* restore exception pointer */
389 mov 8*4(sp),t0 /* get maybe-leaf flag */
390 add $(10*4),sp /* free stackframe */
392 test t0,t0 /* test for maybe-leaf flag */
393 jz L_asm_handle_exception_no_leaf
395 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
396 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
398 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
400 L_asm_handle_exception_no_leaf:
401 jmp *xpc /* jump to exception handler */
403 L_asm_handle_exception_not_catched:
404 mov 4*4(sp),xptr /* restore exception pointer */
405 mov 6*4(sp),itmp3 /* restore data segment pointer */
406 mov 8*4(sp),t0 /* get maybe-leaf flag */
407 add $(10*4),sp /* free stackframe */
410 jz L_asm_handle_exception_no_leaf_stack
412 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
413 xor t0,t0 /* clear the maybe-leaf flag */
415 L_asm_handle_exception_no_leaf_stack:
416 mov FrameSize(itmp3),itmp2 /* get frame size */
417 add sp,itmp2 /* pointer to save area */
419 push xptr /* we are out of registers */
421 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
436 shl $2,itmp1 /* multiply by 4 bytes */
441 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
466 pop xptr /* restore exception pointer */
467 mov FrameSize(itmp3),itmp2 /* get frame size */
468 add itmp2,sp /* unwind stack */
470 pop xpc /* the new xpc is return address */
471 sub $2,xpc /* subtract 2-bytes for call */
473 xor itmp3,itmp3 /* prepare a3 for handle_exception */
475 jmp L_asm_handle_exception_stack_loop
478 /* asm_abstractmethoderror *****************************************************
480 Creates and throws an AbstractMethodError.
482 *******************************************************************************/
484 asm_abstractmethoderror:
485 sub $(2*4),sp /* create stack frame */
486 mov sp,itmp1 /* pass java sp */
489 mov 2*4(sp),itmp2 /* pass exception address */
492 call exceptions_asm_new_abstractmethoderror
493 /* exception pointer is return value */
494 add $(2*4),sp /* remove stack frame */
496 pop xpc /* get exception address */
497 sub $2,xpc /* exception address is ra - 2 */
498 jmp L_asm_handle_exception
501 /* asm_wrapper_patcher *********************************************************
508 16 pointer to virtual java_objectheader
509 12 last byte of machine code (xmcode)
510 8 machine code (which is patched back later)
511 4 unresolved field reference
512 0 patcher function pointer to call
514 *******************************************************************************/
517 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
519 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
520 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
522 mov sp,itmp1 /* create stackframe info */
524 mov itmp1,0*4(sp) /* stackframeinfo pointer */
525 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
527 add $((7+2+4)*4+sizestackframeinfo),itmp2
528 mov itmp2,2*4(sp) /* pass Java sp */
529 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
530 mov itmp3,3*4(sp) /* pass ra to java function */
531 call stacktrace_create_inline_stackframeinfo
533 mov sp,itmp1 /* pass stack pointer */
534 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
536 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
537 call *itmp1 /* call the patcher function */
538 mov v0,1*4(sp) /* save return value */
540 mov sp,itmp1 /* remove stackframe info */
542 mov itmp1,0*4(sp) /* stackframeinfo pointer */
543 call stacktrace_remove_stackframeinfo
545 mov 1*4(sp),itmp3 /* restore return value */
546 test itmp3,itmp3 /* exception thrown? */
547 jz L_asm_wrapper_patcher_exception
549 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
550 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
551 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
552 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
554 ret /* call new patched code */
556 L_asm_wrapper_patcher_exception:
557 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
559 #if defined(ENABLE_THREADS)
560 call builtin_asm_get_exceptionptrptr
563 lea _exceptionptr,itmp2
565 mov (itmp2),xptr /* get the exception pointer */
566 movl $0,(itmp2) /* clear the exception pointer */
568 pop xpc /* get and remove return address */
569 jmp L_asm_handle_exception
572 /* asm_replacement_out *********************************************************
574 This code is jumped to from the replacement-out stubs that are executed
575 when a thread reaches an activated replacement point.
577 The purpose of asm_replacement_out is to read out the parts of the
578 execution state that cannot be accessed from C code, store this state,
579 and then call the C function replace_me.
582 4 start of stack inside method to replace
583 0 rplpoint * info on the replacement point that was reached
585 *******************************************************************************/
587 /* some room to accomodate changes of the stack frame size during replacement */
588 /* XXX we should find a cleaner solution here */
589 #define REPLACEMENT_ROOM 512
592 /* create stack frame */
593 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
595 /* save registers in execution state */
596 mov %eax,(EAX*8+offes_intregs)(sp)
597 mov %ebx,(EBX*8+offes_intregs)(sp)
598 mov %ecx,(ECX*8+offes_intregs)(sp)
599 mov %edx,(EDX*8+offes_intregs)(sp)
600 mov %esi,(ESI*8+offes_intregs)(sp)
601 mov %edi,(EDI*8+offes_intregs)(sp)
602 mov %ebp,(EBP*8+offes_intregs)(sp)
603 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
606 /* clear high 32bit */
607 movl $0,(4+0*8+offes_intregs)(sp)
608 movl $0,(4+1*8+offes_intregs)(sp)
609 movl $0,(4+2*8+offes_intregs)(sp)
610 movl $0,(4+3*8+offes_intregs)(sp)
611 movl $0,(4+4*8+offes_intregs)(sp)
612 movl $0,(4+5*8+offes_intregs)(sp)
613 movl $0,(4+6*8+offes_intregs)(sp)
614 movl $0,(4+7*8+offes_intregs)(sp)
617 /* calculate sp of method */
619 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
620 mov itmp1,(offes_sp)(sp)
622 /* pv must be looked up via AVL tree */
623 movl $0,(offes_pv)(sp)
625 /* call replace_me */
626 mov -4(itmp1),itmp1 /* rplpoint * */
627 push sp /* arg1: execution state */
628 push itmp1 /* arg0: replacement point */
629 call replace_me /* call C function replace_me */
630 call abort /* NEVER REACHED */
632 /* asm_replacement_in **********************************************************
634 This code writes the given execution state and jumps to the replacement
637 This function never returns!
640 void asm_replacement_in(executionstate *es);
642 *******************************************************************************/
645 mov 4(sp),%ebp /* executionstate *es */
648 mov (offes_sp)(%ebp),%esp
650 /* store address of new code */
651 push (offes_pc)(%ebp)
653 /* copy registers from execution state */
654 mov (EAX*8+offes_intregs)(%ebp),%eax
655 mov (EBX*8+offes_intregs)(%ebp),%ebx
656 mov (ECX*8+offes_intregs)(%ebp),%ecx
657 mov (EDX*8+offes_intregs)(%ebp),%edx
658 mov (ESI*8+offes_intregs)(%ebp),%esi
659 mov (EDI*8+offes_intregs)(%ebp),%edi
661 mov (EBP*8+offes_intregs)(%ebp),%ebp
663 /* jump to new code */
666 /************************ function asm_builtin_x2x *****************************
668 * Wrapper functions for corner cases *
670 *******************************************************************************/
701 asm_getclassvalues_atomic:
703 mov 4(%esp),%ecx /* super */
704 mov 8(%esp),%edx /* sub */
706 mov offbaseval(%ecx),%eax
707 mov offdiffval(%ecx),%ecx
708 mov offbaseval(%edx),%edx
711 mov 16(%esp),%ebx /* out */
712 mov %eax,offcast_super_baseval(%ebx)
713 mov %ecx,offcast_super_diffval(%ebx)
714 mov %edx,offcast_sub_baseval(%ebx)
720 asm_criticalsections:
721 #if defined(ENABLE_THREADS)
734 /* Disable exec-stacks, required for Gentoo ***********************************/
736 #if defined(__GCC__) && defined(__ELF__)
737 .section .note.GNU-stack,"",@progbits
741 /* asm_get_cycle_count *********************************************************
743 Get the current time-stamp counter from the CPU.
745 *******************************************************************************/
753 * These are local overrides for various environment variables in Emacs.
754 * Please do not remove this and leave it at the end of the file, where
755 * Emacs will automagically detect them.
756 * ---------------------------------------------------------------------
759 * indent-tabs-mode: t
763 * vim:noexpandtab:sw=4:ts=4: