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
32 #include "vm/jit/i386/arch.h"
33 #include "vm/jit/i386/md-abi.h"
35 #include "vm/jit/abi-asm.h"
36 #include "vm/jit/methodheader.h"
42 /* export functions ***********************************************************/
46 .globl asm_vm_call_method
47 .globl asm_vm_call_method_int
48 .globl asm_vm_call_method_long
49 .globl asm_vm_call_method_float
50 .globl asm_vm_call_method_double
51 .globl asm_vm_call_method_exception_handler
52 .globl asm_vm_call_method_end
54 .globl asm_call_jit_compiler
55 .globl asm_handle_nat_exception
56 .globl asm_handle_exception
58 .globl asm_abstractmethoderror
60 .globl asm_patcher_wrapper
62 #if defined(ENABLE_REPLACEMENT)
63 .globl asm_replacement_out
64 .globl asm_replacement_in
67 .globl asm_builtin_f2i
68 .globl asm_builtin_f2l
69 .globl asm_builtin_d2i
70 .globl asm_builtin_d2l
72 .globl asm_compare_and_swap
73 .globl asm_memory_barrier
75 .globl asm_get_cycle_count
78 /* asm_md_init *****************************************************************
80 Initialize machine dependent stuff.
82 See: http://www.srware.com/linux_numerics.txt
84 This puts the X86 FPU in 64-bit precision mode. The default under
85 Linux is to use 80-bit mode, which produces subtle differences from
86 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
87 64-bit mode, 299 in 80-bit mode.
89 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
91 *******************************************************************************/
94 sub $4,sp /* allocate space for the FPU state */
95 fnstcw (sp) /* get the FPU state */
97 and $0xfcff,%ax /* remove the extended mode flag */
98 or $0x0200,%ax /* put the double mode flag */
99 mov %eax,(sp) /* store new FPU state */
100 fldcw (sp) /* setup new FPU state */
105 /********************* function asm_calljavafunction ***************************
107 * This function calls a Java-method (which possibly needs compilation) *
108 * with up to 4 address parameters. *
110 * This functions calls the JIT-compiler which eventually translates the *
111 * method into machine code. *
114 * javaobject_header *asm_vm_call_method(methodinfo *m, *
115 * u4 count, u4 size, void *callblock); *
117 *******************************************************************************/
121 .long 0 /* catch type all */
122 .long 0 /* handler pc */
124 .long 0 /* start pc */
125 .long 1 /* extable size */
126 .long 0 /* line number table start */
127 .long 0 /* line number table size */
128 .long 0 /* fltsave */
129 .long 0 /* intsave */
132 .long 0 /* frame size */
133 .long 0 /* codeinfo pointer */
136 asm_vm_call_method_int:
137 asm_vm_call_method_long:
138 asm_vm_call_method_float:
139 asm_vm_call_method_double:
141 mov sp,bp /* save stackptr */
142 sub $(4*4),sp /* create stackframe */
143 and $0xfffffff0,sp /* align stack to 16-byte */
145 mov t0,0*4(sp) /* save registers */
149 mov sp,s1 /* save stack pointer */
151 mov 3*4(bp),t0 /* address of data structure */
152 mov 4*4(bp),itmp1 /* number of stack arguments */
155 je L_asm_vm_call_method_stack_copy_done
158 add $1,itmp2 /* keep stack 16-byte aligned */
159 and $0xfffffffe,itmp2
160 shl $3,itmp2 /* calculate stack size */
161 sub itmp2,sp /* create stack frame */
162 mov sp,itmp2 /* temporary stack pointer */
164 L_asm_vm_call_method_stack_copy_loop:
165 mov 0(t0),itmp3 /* load argument */
166 mov itmp3,0(itmp2) /* store argument on stack */
170 sub $1,itmp1 /* subtract 1 argument */
171 add $8,t0 /* set address of next argument */
172 add $8,itmp2 /* increase SP */
175 jg L_asm_vm_call_method_stack_copy_loop
177 L_asm_vm_call_method_stack_copy_done:
178 lea (2*4-256)(bp),mptr /* We subtract 256 to force the next */
179 /* move instruction to have a 32-bit */
182 mov (0*4+256)(mptr),itmp3 /* method call as in Java */
183 call *itmp3 /* call JIT compiler */
185 L_asm_vm_call_method_return:
186 mov s1,sp /* restore stackpointer */
188 mov 0*4(sp),t0 /* restore registers */
195 asm_vm_call_method_exception_handler:
196 push xptr /* pass exception pointer */
197 call builtin_throw_exception
199 asm_vm_call_method_end:
200 jmp L_asm_vm_call_method_return
203 /* asm_call_jit_compiler *******************************************************
205 Invokes the compiler for untranslated JavaVM methods.
207 Register R0 contains a pointer to the method info structure (prepared
208 by createcompilerstub). Using the return address in R26 and the
209 offset in the LDA instruction or using the value in methodptr R28 the
210 patching address for storing the method address can be computed:
212 Method address was either loaded using
214 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
215 i386_call_reg(REG_ITMP2)
219 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
220 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
221 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
222 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
223 i386_call_reg(REG_ITMP1)
225 In the static case the method pointer can be computed using the
226 return address and the lda function following the jmp instruction.
228 *******************************************************************************/
230 asm_call_jit_compiler:
231 L_asm_call_jit_compiler: /* required for PIC code */
232 sub $(4*4),sp /* keep stack 16-byte aligned */
234 mov itmp1,0*4(sp) /* pass methodinfo pointer */
235 mov mptr,1*4(sp) /* pass method pointer */
236 mov sp,itmp2 /* pass java sp */
239 mov 4*4(sp),itmp3 /* pass java ra */
243 add $(4*4),sp /* remove stack frame */
245 test v0,v0 /* check for exception */
246 je L_asm_call_jit_compiler_exception
248 jmp *v0 /* ...and now call the new method */
250 L_asm_call_jit_compiler_exception:
251 call exceptions_get_and_clear_exception
253 pop xpc /* get return address */
254 sub $2,xpc /* faulting address is ra - 2 */
255 jmp L_asm_handle_exception
258 /* asm_handle_exception ********************************************************
260 * This function handles an exception. It does not use the usual calling *
261 * conventions. The exception pointer is passed in REG_ITMP1 and the *
262 * pc from the exception raising position is passed in REG_ITMP2. It searches *
263 * the local exception table for a handler. If no one is found, it unwinds *
264 * stacks and continues searching the callers. *
266 *******************************************************************************/
268 asm_handle_nat_exception:
269 add $4,sp /* clear return address of native stub*/
271 asm_handle_exception:
272 L_asm_handle_exception: /* required for PIC code */
273 sub $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned */
275 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
276 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
278 mov $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
279 mov $1,t0 /* set maybe-leaf flag */
281 L_asm_handle_exception_stack_loop:
282 sub $(12*4),sp /* keep stack 16-byte aligned */
283 mov xptr,4*4(sp) /* save exception pointer */
284 mov xpc,5*4(sp) /* save exception pc */
285 add sp,itmp3 /* calculate Java sp into a3... */
287 mov itmp3,7*4(sp) /* ...and save it */
288 mov t0,8*4(sp) /* save maybe-leaf flag */
290 mov xpc,0*4(sp) /* pass exception pc */
291 call codegen_get_pv_from_pc
292 mov v0,6*4(sp) /* save data segment pointer */
294 mov 4*4(sp),itmp3 /* pass exception pointer */
296 mov 5*4(sp),itmp3 /* pass exception pc */
298 mov v0,2*4(sp) /* pass data segment pointer */
299 mov 7*4(sp),itmp3 /* pass Java stack pointer */
301 call exceptions_handle_exception
304 jz L_asm_handle_exception_not_catched
306 mov v0,xpc /* move handlerpc into xpc */
307 mov 4*4(sp),xptr /* restore exception pointer */
308 mov 8*4(sp),t0 /* get maybe-leaf flag */
309 add $(12*4),sp /* free stackframe */
311 test t0,t0 /* test for maybe-leaf flag */
312 jz L_asm_handle_exception_no_leaf
314 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
315 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
317 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
319 L_asm_handle_exception_no_leaf:
320 jmp *xpc /* jump to exception handler */
322 L_asm_handle_exception_not_catched:
323 mov 4*4(sp),xptr /* restore exception pointer */
324 mov 6*4(sp),itmp3 /* restore data segment pointer */
325 mov 8*4(sp),t0 /* get maybe-leaf flag */
326 add $(12*4),sp /* free stackframe */
329 jz L_asm_handle_exception_no_leaf_stack
331 add $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe */
332 xor t0,t0 /* clear the maybe-leaf flag */
334 L_asm_handle_exception_no_leaf_stack:
335 mov FrameSize(itmp3),itmp2 /* get frame size */
336 add sp,itmp2 /* pointer to save area */
338 push xptr /* we are out of registers */
340 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
355 shl $2,itmp1 /* multiply by 4 bytes */
360 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
385 pop xptr /* restore exception pointer */
386 mov FrameSize(itmp3),itmp2 /* get frame size */
387 add itmp2,sp /* unwind stack */
389 pop xpc /* the new xpc is return address */
390 sub $2,xpc /* subtract 2-bytes for call */
392 xor itmp3,itmp3 /* prepare a3 for handle_exception */
394 jmp L_asm_handle_exception_stack_loop
397 /* asm_abstractmethoderror *****************************************************
399 Creates and throws an AbstractMethodError.
401 *******************************************************************************/
403 asm_abstractmethoderror:
404 sub $(3*4),sp /* keep stack 16-byte aligned */
405 mov sp,itmp1 /* pass java sp */
408 mov 3*4(sp),itmp2 /* pass exception address */
411 call exceptions_asm_new_abstractmethoderror
412 /* exception pointer is return value */
413 add $(3*4),sp /* remove stack frame */
415 pop xpc /* get exception address */
416 sub $2,xpc /* exception address is ra - 2 */
417 jmp L_asm_handle_exception
420 /* asm_patcher_wrapper *********************************************************
427 16 pointer to virtual java_objectheader
428 12 last byte of machine code (xmcode)
429 8 machine code (which is patched back later)
430 4 unresolved field reference
431 0 patcher function pointer to call
433 *******************************************************************************/
436 sub $((1+4+4)*4),sp /* keep stack 16-byte aligned */
438 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
439 mov itmp2,(1+4)*4(sp)
441 mov sp,itmp1 /* pass SP of patcher stub */
442 add $((1+4+4)*4),itmp1
444 movl $0,1*4(sp) /* pass PV (if NULL, use findmethod) */
445 movl $0,2*4(sp) /* pass RA (it's on the stack) */
447 mov v0,itmp3 /* save return value */
449 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
450 mov (1+4)*4(sp),itmp2
452 test itmp3,itmp3 /* exception thrown? */
453 jne L_asm_patcher_wrapper_exception
455 mov (5+1+4+4)*4(sp),itmp3 /* restore itmp3 */
456 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
458 ret /* jump to new patched code */
460 L_asm_patcher_wrapper_exception:
461 add $((6+1+4+4)*4),sp /* remove stack frame, keep RA */
462 mov itmp3,xptr /* get exception */
463 pop xpc /* get and remove return address */
464 jmp L_asm_handle_exception
466 #if defined(ENABLE_REPLACEMENT)
468 /* asm_replacement_out *********************************************************
470 This code is jumped to from the replacement-out stubs that are executed
471 when a thread reaches an activated replacement point.
473 The purpose of asm_replacement_out is to read out the parts of the
474 execution state that cannot be accessed from C code, store this state,
475 and then call the C function replace_me.
478 4 start of stack inside method to replace
479 0 rplpoint * info on the replacement point that was reached
481 *******************************************************************************/
483 /* some room to accomodate changes of the stack frame size during replacement */
484 /* XXX we should find a cleaner solution here */
485 #define REPLACEMENT_ROOM 512
488 /* create stack frame */
489 sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
491 /* save registers in execution state */
492 mov %eax,(EAX*4+offes_intregs)(sp)
493 mov %ebx,(EBX*4+offes_intregs)(sp)
494 mov %ecx,(ECX*4+offes_intregs)(sp)
495 mov %edx,(EDX*4+offes_intregs)(sp)
496 mov %esi,(ESI*4+offes_intregs)(sp)
497 mov %edi,(EDI*4+offes_intregs)(sp)
498 mov %ebp,(EBP*4+offes_intregs)(sp)
499 movl $0 ,(ESP*4+offes_intregs)(sp) /* not used */
501 /* calculate sp of method */
503 add $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
504 mov itmp1,(offes_sp)(sp)
506 /* pv must be looked up via AVL tree */
507 movl $0,(offes_pv)(sp)
509 /* call replace_me */
510 mov -4(itmp1),itmp1 /* rplpoint * */
511 push sp /* arg1: execution state */
512 push itmp1 /* arg0: replacement point */
513 call replace_me /* call C function replace_me */
516 /* asm_replacement_in **********************************************************
518 This code writes the given execution state and jumps to the replacement
521 This function never returns!
524 void asm_replacement_in(executionstate *es, replace_safestack_t *st);
526 *******************************************************************************/
530 mov 8(sp),%esi /* replace_safestack_t *st */
531 mov 4(sp),%ebp /* executionstate *es == safe stack */
533 /* switch to the safe stack and build a stack frame */
537 /* call replace_build_execution_state(st) */
539 call replace_build_execution_state
542 mov (offes_sp)(%ebp),sp
544 /* push address of new code */
545 push (offes_pc)(%ebp)
547 /* allocate an executionstate_t on the stack */
548 sub $(sizeexecutionstate),sp
550 /* call replace_free_safestack(st,& of allocated executionstate_t) */
553 call replace_free_safestack
556 /* copy registers from execution state */
557 mov (EAX*4+offes_intregs)(sp),%eax
558 mov (EBX*4+offes_intregs)(sp),%ebx
559 mov (ECX*4+offes_intregs)(sp),%ecx
560 mov (EDX*4+offes_intregs)(sp),%edx
561 mov (ESI*4+offes_intregs)(sp),%esi
562 mov (EDI*4+offes_intregs)(sp),%edi
563 mov (EBP*4+offes_intregs)(sp),%ebp
565 /* pop the execution state off the stack */
566 add $(sizeexecutionstate),sp
568 /* jump to new code, hold your thumbs! ;) */
571 #endif /* defined(ENABLE_REPLACEMENT) */
574 /************************ function asm_builtin_x2x *****************************
576 * Wrapper functions for corner cases *
578 *******************************************************************************/
609 /* asm_compare_and_swap ********************************************************
611 Does an atomic compare and swap. Required for the lock
614 Atomically do the following: Check if the location still contains
615 `oldval`. If so, replace it by `newval` and return `oldval`.
620 long compare_and_swap(volatile long *p, long oldval, long newval);
622 *******************************************************************************/
624 asm_compare_and_swap:
625 mov 1*4(sp),%ecx /* load p into a register */
626 mov 2*4(sp),%eax /* load oldval into return register */
627 mov 3*4(sp),%edx /* load newval into a register */
628 lock; cmpxchgl %edx,0(%ecx)
632 /* asm_memory_barrier **********************************************************
634 A memory barrier for the Java Memory Model.
636 *******************************************************************************/
643 /* asm_get_cycle_count *********************************************************
645 Get the current time-stamp counter from the CPU.
647 *******************************************************************************/
654 /* disable exec-stacks ********************************************************/
656 #if defined(__linux__) && defined(__ELF__)
657 .section .note.GNU-stack,"",%progbits
662 * These are local overrides for various environment variables in Emacs.
663 * Please do not remove this and leave it at the end of the file, where
664 * Emacs will automagically detect them.
665 * ---------------------------------------------------------------------
668 * indent-tabs-mode: t
672 * vim:noexpandtab:sw=4:ts=4: