1 /* src/vm/jit/i386/asmpart.S - Java-C interface functions for i386
3 Copyright (C) 1996-2005, 2006, 2007 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 $Id: asmpart.S 8210 2007-07-18 12:51:00Z twisti $
34 #include "vm/jit/i386/arch.h"
35 #include "vm/jit/i386/md-abi.h"
36 #include "vm/jit/i386/offsets.h"
38 #include "vm/jit/abi-asm.h"
39 #include "vm/jit/methodheader.h"
45 /* export functions ***********************************************************/
49 .globl asm_vm_call_method
50 .globl asm_vm_call_method_int
51 .globl asm_vm_call_method_long
52 .globl asm_vm_call_method_float
53 .globl asm_vm_call_method_double
54 .globl asm_vm_call_method_exception_handler
55 .globl asm_vm_call_method_end
57 .globl asm_call_jit_compiler
58 .globl asm_handle_nat_exception
59 .globl asm_handle_exception
61 .globl asm_abstractmethoderror
63 .globl asm_patcher_wrapper
65 #if defined(ENABLE_REPLACEMENT)
66 .globl asm_replacement_out
67 .globl asm_replacement_in
70 .globl asm_builtin_f2i
71 .globl asm_builtin_f2l
72 .globl asm_builtin_d2i
73 .globl asm_builtin_d2l
75 .globl asm_compare_and_swap
76 .globl asm_memory_barrier
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 sp,s1 /* save stack pointer */
157 mov 3*4(bp),t0 /* address of data structure */
158 mov 4*4(bp),itmp1 /* number of stack arguments */
161 je L_asm_vm_call_method_stack_copy_done
164 add $1,itmp2 /* keep stack 16-byte aligned */
165 and $0xfffffffe,itmp2
166 shl $3,itmp2 /* calculate stack size */
167 sub itmp2,sp /* create stack frame */
168 mov sp,itmp2 /* temporary stack pointer */
170 L_asm_vm_call_method_stack_copy_loop:
171 mov 0(t0),itmp3 /* load argument */
172 mov itmp3,0(itmp2) /* store argument on stack */
176 sub $1,itmp1 /* subtract 1 argument */
177 add $8,t0 /* set address of next argument */
178 add $8,itmp2 /* increase SP */
181 jg L_asm_vm_call_method_stack_copy_loop
183 L_asm_vm_call_method_stack_copy_done:
184 lea (2*4-256)(bp),mptr /* We subtract 256 to force the next */
185 /* move instruction to have a 32-bit */
188 mov (0*4+256)(mptr),itmp3 /* method call as in Java */
189 call *itmp3 /* call JIT compiler */
191 L_asm_vm_call_method_return:
192 mov s1,sp /* restore stackpointer */
194 mov 0*4(sp),t0 /* restore registers */
201 asm_vm_call_method_exception_handler:
202 push xptr /* pass exception pointer */
203 call builtin_throw_exception
205 asm_vm_call_method_end:
206 jmp L_asm_vm_call_method_return
209 /* asm_call_jit_compiler *******************************************************
211 Invokes the compiler for untranslated JavaVM methods.
213 Register R0 contains a pointer to the method info structure (prepared
214 by createcompilerstub). Using the return address in R26 and the
215 offset in the LDA instruction or using the value in methodptr R28 the
216 patching address for storing the method address can be computed:
218 Method address was either loaded using
220 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
221 i386_call_reg(REG_ITMP2)
225 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
226 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
227 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
228 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
229 i386_call_reg(REG_ITMP1)
231 In the static case the method pointer can be computed using the
232 return address and the lda function following the jmp instruction.
234 *******************************************************************************/
236 asm_call_jit_compiler:
237 L_asm_call_jit_compiler: /* required for PIC code */
238 sub $(4*4),sp /* keep stack 16-byte aligned */
240 mov itmp1,0*4(sp) /* pass methodinfo pointer */
241 mov mptr,1*4(sp) /* pass method pointer */
242 mov sp,itmp2 /* pass java sp */
245 mov 4*4(sp),itmp3 /* pass java ra */
249 add $(4*4),sp /* remove stack frame */
251 test v0,v0 /* check for exception */
252 je L_asm_call_jit_compiler_exception
254 jmp *v0 /* ...and now call the new method */
256 L_asm_call_jit_compiler_exception:
257 call exceptions_get_and_clear_exception
259 pop xpc /* get return address */
260 sub $2,xpc /* faulting address is ra - 2 */
261 jmp L_asm_handle_exception
264 /* asm_handle_exception ********************************************************
266 * This function handles an exception. It does not use the usual calling *
267 * conventions. The exception pointer is passed in REG_ITMP1 and the *
268 * pc from the exception raising position is passed in REG_ITMP2. It searches *
269 * the local exception table for a handler. If no one is found, it unwinds *
270 * stacks and continues searching the callers. *
272 *******************************************************************************/
274 asm_handle_nat_exception:
275 add $4,sp /* clear return address of native stub*/
277 asm_handle_exception:
278 L_asm_handle_exception: /* required for PIC code */
279 sub $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned */
281 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
282 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
284 mov $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
285 mov $1,t0 /* set maybe-leaf flag */
287 L_asm_handle_exception_stack_loop:
288 sub $(12*4),sp /* keep stack 16-byte aligned */
289 mov xptr,4*4(sp) /* save exception pointer */
290 mov xpc,5*4(sp) /* save exception pc */
291 add sp,itmp3 /* calculate Java sp into a3... */
293 mov itmp3,7*4(sp) /* ...and save it */
294 mov t0,8*4(sp) /* save maybe-leaf flag */
296 mov xpc,0*4(sp) /* pass exception pc */
297 call codegen_get_pv_from_pc
298 mov v0,6*4(sp) /* save data segment pointer */
300 mov 4*4(sp),itmp3 /* pass exception pointer */
302 mov 5*4(sp),itmp3 /* pass exception pc */
304 mov v0,2*4(sp) /* pass data segment pointer */
305 mov 7*4(sp),itmp3 /* pass Java stack pointer */
307 call exceptions_handle_exception
310 jz L_asm_handle_exception_not_catched
312 mov v0,xpc /* move handlerpc into xpc */
313 mov 4*4(sp),xptr /* restore exception pointer */
314 mov 8*4(sp),t0 /* get maybe-leaf flag */
315 add $(12*4),sp /* free stackframe */
317 test t0,t0 /* test for maybe-leaf flag */
318 jz L_asm_handle_exception_no_leaf
320 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
321 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
323 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
325 L_asm_handle_exception_no_leaf:
326 jmp *xpc /* jump to exception handler */
328 L_asm_handle_exception_not_catched:
329 mov 4*4(sp),xptr /* restore exception pointer */
330 mov 6*4(sp),itmp3 /* restore data segment pointer */
331 mov 8*4(sp),t0 /* get maybe-leaf flag */
332 add $(12*4),sp /* free stackframe */
335 jz L_asm_handle_exception_no_leaf_stack
337 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
338 xor t0,t0 /* clear the maybe-leaf flag */
340 L_asm_handle_exception_no_leaf_stack:
341 mov FrameSize(itmp3),itmp2 /* get frame size */
342 add sp,itmp2 /* pointer to save area */
344 push xptr /* we are out of registers */
346 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
361 shl $2,itmp1 /* multiply by 4 bytes */
366 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
391 pop xptr /* restore exception pointer */
392 mov FrameSize(itmp3),itmp2 /* get frame size */
393 add itmp2,sp /* unwind stack */
395 pop xpc /* the new xpc is return address */
396 sub $2,xpc /* subtract 2-bytes for call */
398 xor itmp3,itmp3 /* prepare a3 for handle_exception */
400 jmp L_asm_handle_exception_stack_loop
403 /* asm_abstractmethoderror *****************************************************
405 Creates and throws an AbstractMethodError.
407 *******************************************************************************/
409 asm_abstractmethoderror:
410 sub $(3*4),sp /* keep stack 16-byte aligned */
411 mov sp,itmp1 /* pass java sp */
414 mov 3*4(sp),itmp2 /* pass exception address */
417 call exceptions_asm_new_abstractmethoderror
418 /* exception pointer is return value */
419 add $(3*4),sp /* remove stack frame */
421 pop xpc /* get exception address */
422 sub $2,xpc /* exception address is ra - 2 */
423 jmp L_asm_handle_exception
426 /* asm_patcher_wrapper *********************************************************
433 16 pointer to virtual java_objectheader
434 12 last byte of machine code (xmcode)
435 8 machine code (which is patched back later)
436 4 unresolved field reference
437 0 patcher function pointer to call
439 *******************************************************************************/
442 sub $((1+4+4)*4),sp /* keep stack 16-byte aligned */
444 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
445 mov itmp2,(1+4)*4(sp)
447 mov sp,itmp1 /* pass SP of patcher stub */
448 add $((1+4+4)*4),itmp1
450 movl $0,1*4(sp) /* pass PV (if NULL, use findmethod) */
451 movl $0,2*4(sp) /* pass RA (it's on the stack) */
453 mov v0,itmp3 /* save return value */
455 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
456 mov (1+4)*4(sp),itmp2
458 test itmp3,itmp3 /* exception thrown? */
459 jne L_asm_patcher_wrapper_exception
461 mov (5+1+4+4)*4(sp),itmp3 /* restore itmp3 */
462 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
464 ret /* jump to new patched code */
466 L_asm_patcher_wrapper_exception:
467 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
468 mov itmp3,xptr /* get exception */
469 pop xpc /* get and remove return address */
470 jmp L_asm_handle_exception
472 #if defined(ENABLE_REPLACEMENT)
474 /* asm_replacement_out *********************************************************
476 This code is jumped to from the replacement-out stubs that are executed
477 when a thread reaches an activated replacement point.
479 The purpose of asm_replacement_out is to read out the parts of the
480 execution state that cannot be accessed from C code, store this state,
481 and then call the C function replace_me.
484 4 start of stack inside method to replace
485 0 rplpoint * info on the replacement point that was reached
487 *******************************************************************************/
489 /* some room to accomodate changes of the stack frame size during replacement */
490 /* XXX we should find a cleaner solution here */
491 #define REPLACEMENT_ROOM 512
494 /* create stack frame */
495 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
497 /* save registers in execution state */
498 mov %eax,(EAX*4+offes_intregs)(sp)
499 mov %ebx,(EBX*4+offes_intregs)(sp)
500 mov %ecx,(ECX*4+offes_intregs)(sp)
501 mov %edx,(EDX*4+offes_intregs)(sp)
502 mov %esi,(ESI*4+offes_intregs)(sp)
503 mov %edi,(EDI*4+offes_intregs)(sp)
504 mov %ebp,(EBP*4+offes_intregs)(sp)
505 movl $0 ,(ESP*4+offes_intregs)(sp) /* not used */
507 /* calculate sp of method */
509 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
510 mov itmp1,(offes_sp)(sp)
512 /* pv must be looked up via AVL tree */
513 movl $0,(offes_pv)(sp)
515 /* call replace_me */
516 mov -4(itmp1),itmp1 /* rplpoint * */
517 push sp /* arg1: execution state */
518 push itmp1 /* arg0: replacement point */
519 call replace_me /* call C function replace_me */
522 /* asm_replacement_in **********************************************************
524 This code writes the given execution state and jumps to the replacement
527 This function never returns!
530 void asm_replacement_in(executionstate *es, replace_safestack_t *st);
532 *******************************************************************************/
536 mov 8(sp),%esi /* replace_safestack_t *st */
537 mov 4(sp),%ebp /* executionstate *es == safe stack */
539 /* switch to the safe stack and build a stack frame */
543 /* call replace_build_execution_state(st) */
545 call replace_build_execution_state
548 mov (offes_sp)(%ebp),sp
550 /* push address of new code */
551 push (offes_pc)(%ebp)
553 /* allocate an executionstate_t on the stack */
554 sub $(sizeexecutionstate),sp
556 /* call replace_free_safestack(st,& of allocated executionstate_t) */
559 call replace_free_safestack
562 /* copy registers from execution state */
563 mov (EAX*4+offes_intregs)(sp),%eax
564 mov (EBX*4+offes_intregs)(sp),%ebx
565 mov (ECX*4+offes_intregs)(sp),%ecx
566 mov (EDX*4+offes_intregs)(sp),%edx
567 mov (ESI*4+offes_intregs)(sp),%esi
568 mov (EDI*4+offes_intregs)(sp),%edi
569 mov (EBP*4+offes_intregs)(sp),%ebp
571 /* pop the execution state off the stack */
572 add $(sizeexecutionstate),sp
574 /* jump to new code, hold your thumbs! ;) */
577 #endif /* defined(ENABLE_REPLACEMENT) */
580 /************************ function asm_builtin_x2x *****************************
582 * Wrapper functions for corner cases *
584 *******************************************************************************/
615 /* asm_compare_and_swap ********************************************************
617 Does an atomic compare and swap. Required for the lock
620 Atomically do the following: Check if the location still contains
621 `oldval`. If so, replace it by `newval` and return `oldval`.
626 long compare_and_swap(volatile long *p, long oldval, long newval);
628 *******************************************************************************/
630 asm_compare_and_swap:
631 mov 1*4(sp),%ecx /* load p into a register */
632 mov 2*4(sp),%eax /* load oldval into return register */
633 mov 3*4(sp),%edx /* load newval into a register */
634 lock; cmpxchgl %edx,0(%ecx)
638 /* asm_memory_barrier **********************************************************
640 A memory barrier for the Java Memory Model.
642 *******************************************************************************/
649 asm_getclassvalues_atomic:
651 mov 4(%esp),%ecx /* super */
652 mov 8(%esp),%edx /* sub */
654 mov offbaseval(%ecx),%eax
655 mov offdiffval(%ecx),%ecx
656 mov offbaseval(%edx),%edx
659 mov 16(%esp),%ebx /* out */
660 mov %eax,offcast_super_baseval(%ebx)
661 mov %ecx,offcast_super_diffval(%ebx)
662 mov %edx,offcast_sub_baseval(%ebx)
668 asm_criticalsections:
669 #if defined(ENABLE_THREADS)
682 /* asm_get_cycle_count *********************************************************
684 Get the current time-stamp counter from the CPU.
686 *******************************************************************************/
693 /* disable exec-stacks ********************************************************/
695 #if defined(__linux__) && defined(__ELF__)
696 .section .note.GNU-stack,"",%progbits
701 * These are local overrides for various environment variables in Emacs.
702 * Please do not remove this and leave it at the end of the file, where
703 * Emacs will automagically detect them.
704 * ---------------------------------------------------------------------
707 * indent-tabs-mode: t
711 * vim:noexpandtab:sw=4:ts=4: