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 5053 2006-06-28 19:11:20Z 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 call exceptions_new_abstractmethoderror
486 /* exception pointer is return value */
487 pop xpc /* get exception address */
488 sub $2,xpc /* exception address is ra - 2 */
489 jmp L_asm_handle_exception
492 /* asm_wrapper_patcher *********************************************************
499 16 pointer to virtual java_objectheader
500 12 last byte of machine code (xmcode)
501 8 machine code (which is patched back later)
502 4 unresolved field reference
503 0 patcher function pointer to call
505 *******************************************************************************/
508 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
510 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
511 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
513 mov sp,itmp1 /* create stackframe info */
515 mov itmp1,0*4(sp) /* stackframeinfo pointer */
516 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
518 add $((7+2+4)*4+sizestackframeinfo),itmp2
519 mov itmp2,2*4(sp) /* pass Java sp */
520 mov ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
521 mov itmp3,3*4(sp) /* pass ra to java function */
522 call stacktrace_create_inline_stackframeinfo
524 mov sp,itmp1 /* pass stack pointer */
525 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
527 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
528 call *itmp1 /* call the patcher function */
529 mov v0,1*4(sp) /* save return value */
531 mov sp,itmp1 /* remove stackframe info */
533 mov itmp1,0*4(sp) /* stackframeinfo pointer */
534 call stacktrace_remove_stackframeinfo
536 mov 1*4(sp),itmp3 /* restore return value */
537 test itmp3,itmp3 /* exception thrown? */
538 jz L_asm_wrapper_patcher_exception
540 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
541 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
542 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
543 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
545 ret /* call new patched code */
547 L_asm_wrapper_patcher_exception:
548 add $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
550 #if defined(ENABLE_THREADS)
551 call builtin_asm_get_exceptionptrptr
554 lea _exceptionptr,itmp2
556 mov (itmp2),xptr /* get the exception pointer */
557 movl $0,(itmp2) /* clear the exception pointer */
559 pop xpc /* get and remove return address */
560 jmp L_asm_handle_exception
563 /* asm_replacement_out *********************************************************
565 This code is jumped to from the replacement-out stubs that are executed
566 when a thread reaches an activated replacement point.
568 The purpose of asm_replacement_out is to read out the parts of the
569 execution state that cannot be accessed from C code, store this state,
570 and then call the C function replace_me.
573 4 start of stack inside method to replace
574 0 rplpoint * info on the replacement point that was reached
576 *******************************************************************************/
578 /* some room to accomodate changes of the stack frame size during replacement */
579 /* XXX we should find a cleaner solution here */
580 #define REPLACEMENT_ROOM 512
583 /* create stack frame */
584 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
586 /* save registers in execution state */
587 mov %eax,(EAX*8+offes_intregs)(sp)
588 mov %ebx,(EBX*8+offes_intregs)(sp)
589 mov %ecx,(ECX*8+offes_intregs)(sp)
590 mov %edx,(EDX*8+offes_intregs)(sp)
591 mov %esi,(ESI*8+offes_intregs)(sp)
592 mov %edi,(EDI*8+offes_intregs)(sp)
593 mov %ebp,(EBP*8+offes_intregs)(sp)
594 movl $0 ,(ESP*8+offes_intregs)(sp) /* not used */
597 /* clear high 32bit */
598 movl $0,(4+0*8+offes_intregs)(sp)
599 movl $0,(4+1*8+offes_intregs)(sp)
600 movl $0,(4+2*8+offes_intregs)(sp)
601 movl $0,(4+3*8+offes_intregs)(sp)
602 movl $0,(4+4*8+offes_intregs)(sp)
603 movl $0,(4+5*8+offes_intregs)(sp)
604 movl $0,(4+6*8+offes_intregs)(sp)
605 movl $0,(4+7*8+offes_intregs)(sp)
608 /* calculate sp of method */
610 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
611 mov itmp1,(offes_sp)(sp)
613 /* pv must be looked up via AVL tree */
614 movl $0,(offes_pv)(sp)
616 /* call replace_me */
617 mov -4(itmp1),itmp1 /* rplpoint * */
618 push sp /* arg1: execution state */
619 push itmp1 /* arg0: replacement point */
620 call replace_me /* call C function replace_me */
621 call abort /* NEVER REACHED */
623 /* asm_replacement_in **********************************************************
625 This code writes the given execution state and jumps to the replacement
628 This function never returns!
631 void asm_replacement_in(executionstate *es);
633 *******************************************************************************/
636 mov 4(sp),%ebp /* executionstate *es */
639 mov (offes_sp)(%ebp),%esp
641 /* store address of new code */
642 push (offes_pc)(%ebp)
644 /* copy registers from execution state */
645 mov (EAX*8+offes_intregs)(%ebp),%eax
646 mov (EBX*8+offes_intregs)(%ebp),%ebx
647 mov (ECX*8+offes_intregs)(%ebp),%ecx
648 mov (EDX*8+offes_intregs)(%ebp),%edx
649 mov (ESI*8+offes_intregs)(%ebp),%esi
650 mov (EDI*8+offes_intregs)(%ebp),%edi
652 mov (EBP*8+offes_intregs)(%ebp),%ebp
654 /* jump to new code */
657 /************************ function asm_builtin_x2x *****************************
659 * Wrapper functions for corner cases *
661 *******************************************************************************/
692 asm_getclassvalues_atomic:
694 mov 4(%esp),%ecx /* super */
695 mov 8(%esp),%edx /* sub */
697 mov offbaseval(%ecx),%eax
698 mov offdiffval(%ecx),%ecx
699 mov offbaseval(%edx),%edx
702 mov 16(%esp),%ebx /* out */
703 mov %eax,offcast_super_baseval(%ebx)
704 mov %ecx,offcast_super_diffval(%ebx)
705 mov %edx,offcast_sub_baseval(%ebx)
711 asm_criticalsections:
712 #if defined(ENABLE_THREADS)
725 /* Disable exec-stacks, required for Gentoo ***********************************/
727 #if defined(__GCC__) && defined(__ELF__)
728 .section .note.GNU-stack,"",@progbits
732 /* asm_get_cycle_count *********************************************************
734 Get the current time-stamp counter from the CPU.
736 *******************************************************************************/
744 * These are local overrides for various environment variables in Emacs.
745 * Please do not remove this and leave it at the end of the file, where
746 * Emacs will automagically detect them.
747 * ---------------------------------------------------------------------
750 * indent-tabs-mode: t
754 * vim:noexpandtab:sw=4:ts=4: