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
33 $Id: asmpart.S 4560 2006-03-05 23:35:25Z twisti $
40 #include "vm/jit/abi.h"
41 #include "vm/jit/i386/md-abi.h"
42 #include "vm/jit/i386/md-asm.h"
43 #include "vm/jit/i386/offsets.h"
45 #include "vm/jit/methodheader.h"
51 /* exported functions and variables *******************************************/
55 .globl asm_vm_call_method
56 .globl asm_vm_call_method_int
57 .globl asm_vm_call_method_long
58 .globl asm_vm_call_method_float
59 .globl asm_vm_call_method_double
61 .globl asm_call_jit_compiler
62 .globl asm_handle_nat_exception
63 .globl asm_handle_exception
65 .globl asm_wrapper_patcher
67 .globl asm_builtin_f2i
68 .globl asm_builtin_f2l
69 .globl asm_builtin_d2i
70 .globl asm_builtin_d2l
72 .globl asm_perform_threadswitch
73 .globl asm_initialize_thread_stack
74 .globl asm_switchstackandcall
75 .globl asm_criticalsections
76 .globl asm_getclassvalues_atomic
79 /* asm_md_init *****************************************************************
81 Initialize machine dependent stuff.
83 See: http://www.srware.com/linux_numerics.txt
85 This puts the X86 FPU in 64-bit precision mode. The default under
86 Linux is to use 80-bit mode, which produces subtle differences from
87 FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
88 64-bit mode, 299 in 80-bit mode.
90 Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
92 *******************************************************************************/
95 sub $4,sp /* allocate space for the FPU state */
96 fnstcw (sp) /* get the FPU state */
98 and $0xfcff,%ax /* remove the extended mode flag */
99 or $0x0200,%ax /* put the double mode flag */
100 mov %eax,(sp) /* store new FPU state */
101 fldcw (sp) /* setup new FPU state */
106 /********************* function asm_calljavafunction ***************************
108 * This function calls a Java-method (which possibly needs compilation) *
109 * with up to 4 address parameters. *
111 * This functions calls the JIT-compiler which eventually translates the *
112 * method into machine code. *
115 * javaobject_header *asm_vm_call_method(methodinfo *m, *
116 * u4 count, u4 size, void *callblock); *
118 *******************************************************************************/
122 .long 0 /* catch type all */
123 .long calljava_xhandler2 /* handler pc */
124 .long calljava_xhandler2 /* end pc */
125 .long L_asm_vm_call_method /* start pc */
126 .long 1 /* extable size */
127 .long 0 /* line number table start */
128 .long 0 /* line number table size */
129 .long 0 /* fltsave */
130 .long 0 /* intsave */
133 .long 0 /* frame size */
134 .long 0 /* method pointer (pointer to name) */
137 asm_vm_call_method_int:
138 asm_vm_call_method_long:
139 asm_vm_call_method_float:
140 asm_vm_call_method_double:
141 L_asm_vm_call_method: /* required for PIC code */
143 mov %esp,%ebp /* save stackptr */
145 push %ebx /* save registers */
149 mov 4*4(%ebp),%eax /* pointer to arg block (4(push)+4(return)+4+4)*/
150 mov 3*4(%ebp),%ecx /* arg count (4(push)+4(return)+4 */
152 xor %esi,%esi /* clear stackframe size (MUST be */
153 /* before args check, may be zero!!!) */
154 test %ecx,%ecx /* maybe we have no args */
155 jle calljava_copydone
157 mov %ecx,%edx /* calculate stack size */
158 mov %eax,%edi /* save pointer to arg block */
160 calljava_calcstacksize:
161 mov offvmargtype(%eax),%ebx
162 test $1,%ebx /* two word type? */
163 jz calljava_onewordtype
164 add $4,%esi /* add 1 slot to stackframe size */
166 calljava_onewordtype:
167 add $4,%esi /* add 1 slot to stackframe size */
169 test %edx,%edx /* any args left? */
171 add $sizevmarg,%eax /* goto next argument block */
172 jmp calljava_calcstacksize
175 mov %edi,%eax /* restore pointer to arg block */
176 sub %esi,%esp /* create stackframe for arguments */
177 mov %esp,%edi /* move stackpointer into temp variable */
180 mov offvmargdata(%eax),%edx /* copy 4 Byte of Argument */
182 add $4,%edi /* increase sp to next argument */
183 mov offvmargtype(%eax),%ebx /* type -> ebx */
184 test $1,%ebx /* two word type? */
187 mov offvmargdata+4(%eax),%edx /* copy upper 4 byte of 2 word type */
189 add $4,%edi /* increase sp to next argument */
192 sub $1,%ecx /* are there any args left? */
194 jle calljava_copydone
196 add $sizevmarg,%eax /* goto next argument block */
197 jmp calljava_copyloop
200 mov 2*4(%ebp),itmp1 /* move function pointer to itmp1 */
202 lea L_asm_call_jit_compiler,itmp3
203 call *itmp3 /* call JIT compiler */
205 L_asm_vm_call_method_return:
206 add %esi,%esp /* remove arg stack frame */
207 pop %edi /* restore registers */
214 push xptr /* pass exception pointer */
215 call builtin_throw_exception
217 xor v0,v0 /* return NULL */
218 jmp L_asm_vm_call_method_return
221 /* asm_call_jit_compiler *******************************************************
223 Invokes the compiler for untranslated JavaVM methods.
225 Register R0 contains a pointer to the method info structure (prepared
226 by createcompilerstub). Using the return address in R26 and the
227 offset in the LDA instruction or using the value in methodptr R28 the
228 patching address for storing the method address can be computed:
230 Method address was either loaded using
232 i386_mov_imm_reg(a, REG_ITMP2) ; invokestatic/special
233 i386_call_reg(REG_ITMP2)
237 i386_mov_membase_reg(REG_SP, 0, REG_ITMP1) ; invokevirtual/interface
238 i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
239 i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
240 sizeof(methodptr) * m->vftblindex, REG_ITMP1)
241 i386_call_reg(REG_ITMP1)
243 In the static case the method pointer can be computed using the
244 return address and the lda function following the jmp instruction.
246 *******************************************************************************/
248 asm_call_jit_compiler:
249 L_asm_call_jit_compiler: /* required for PIC code */
250 sub $((4+2)*4+sizestackframeinfo),sp /* create stack frame */
251 mov itmp1,(4+0)*4(sp) /* save method pointer */
253 mov (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address */
254 mov -1(itmp3),itmp1b /* get function code */
255 cmp $0xd1,itmp1b /* called with `call *REG_ITMP2'? */
256 jne L_not_static_special
258 sub $6,itmp3 /* calculate address of immediate */
259 jmp L_call_jit_compile
261 L_not_static_special:
262 cmp $0xd0,itmp1b /* called with `call *REG_ITMP1' */
263 jne L_not_virtual_interface
265 sub $6,itmp3 /* calculate address of offset */
266 mov (itmp3),itmp3 /* get offset */
267 add itmp2,itmp3 /* add base address to get method adr */
268 jmp L_call_jit_compile
270 L_not_virtual_interface:
271 xor itmp3,itmp3 /* a call from asm_calljavafunction */
274 mov itmp3,(4+1)*4(sp) /* save address for method pointer */
276 mov sp,itmp1 /* create stackframe info */
278 mov itmp1,0*4(sp) /* stackframeinfo pointer */
279 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
281 add $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp */
283 mov ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra */
285 call stacktrace_create_inline_stackframeinfo
287 mov (4+0)*4(sp),itmp1 /* pass method pointer */
290 mov v0,(4+0)*4(sp) /* save return value */
292 mov sp,itmp1 /* remove stackframe info */
294 mov itmp1,0*4(sp) /* stackframeinfo pointer */
295 call stacktrace_remove_stackframeinfo
297 mov (4+0)*4(sp),v0 /* restore return value */
298 mov (4+1)*4(sp),itmp3 /* restore address for method pointer */
300 add $((4+2)*4+sizestackframeinfo),sp /* remove stack frame */
302 test v0,v0 /* check for exception */
303 je L_asm_call_jit_compiler_exception
305 test itmp3,itmp3 /* was this a JIT call? */
308 mov v0,(itmp3) /* save the new method pointer */
311 jmp *v0 /* ...and now call the new method */
313 L_asm_call_jit_compiler_exception:
314 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
315 call builtin_asm_get_exceptionptrptr
316 mov v0,itmp2 /* v0 == itmp1 */
318 lea _exceptionptr,itmp2
320 mov (itmp2),xptr /* get the exception pointer */
321 movl $0,(itmp2) /* clear the exception pointer */
323 pop xpc /* get return address */
324 sub $2,xpc /* faulting address is ra - 2 */
325 jmp L_asm_handle_exception
328 /* asm_handle_exception ********************************************************
330 * This function handles an exception. It does not use the usual calling *
331 * conventions. The exception pointer is passed in REG_ITMP1 and the *
332 * pc from the exception raising position is passed in REG_ITMP2. It searches *
333 * the local exception table for a handler. If no one is found, it unwinds *
334 * stacks and continues searching the callers. *
336 *******************************************************************************/
338 asm_handle_nat_exception:
339 add $4,sp /* clear return address of native stub*/
341 asm_handle_exception:
342 L_asm_handle_exception: /* required for PIC code */
343 sub $((ARG_CNT+TMP_CNT)*4),sp /* create maybe-leaf stackframe */
345 SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
346 SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
348 mov $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception */
349 mov $1,t0 /* set maybe-leaf flag */
351 L_asm_handle_exception_stack_loop:
352 sub $(10*4),sp /* create stackframe */
353 mov xptr,4*4(sp) /* save exception pointer */
354 mov xpc,5*4(sp) /* save exception pc */
355 add sp,itmp3 /* calculate Java sp into a3... */
357 mov itmp3,7*4(sp) /* ...and save it */
358 mov t0,8*4(sp) /* save maybe-leaf flag */
360 mov xpc,0*4(sp) /* pass exception pc */
361 call codegen_findmethod
362 mov v0,6*4(sp) /* save data segment pointer */
364 mov 4*4(sp),itmp3 /* pass exception pointer */
366 mov 5*4(sp),itmp3 /* pass exception pc */
368 mov v0,2*4(sp) /* pass data segment pointer */
369 mov 7*4(sp),itmp3 /* pass Java stack pointer */
371 call exceptions_handle_exception
374 jz L_asm_handle_exception_not_catched
376 mov v0,xpc /* move handlerpc into xpc */
377 mov 4*4(sp),xptr /* restore exception pointer */
378 mov 8*4(sp),t0 /* get maybe-leaf flag */
379 add $(10*4),sp /* free stackframe */
381 test t0,t0 /* test for maybe-leaf flag */
382 jz L_asm_handle_exception_no_leaf
384 RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
385 RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
387 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
389 L_asm_handle_exception_no_leaf:
390 jmp *xpc /* jump to exception handler */
392 L_asm_handle_exception_not_catched:
393 mov 4*4(sp),xptr /* restore exception pointer */
394 mov 6*4(sp),itmp3 /* restore data segment pointer */
395 mov 8*4(sp),t0 /* get maybe-leaf flag */
396 add $(10*4),sp /* free stackframe */
399 jz L_asm_handle_exception_no_leaf_stack
401 add $((ARG_CNT+TMP_CNT)*4),sp /* remove maybe-leaf stackframe */
402 xor t0,t0 /* clear the maybe-leaf flag */
404 L_asm_handle_exception_no_leaf_stack:
405 mov FrameSize(itmp3),itmp2 /* get frame size */
406 add sp,itmp2 /* pointer to save area */
408 push xptr /* we are out of registers */
410 mov IntSave(itmp3),itmp1 /* itmp1 = saved int register count */
425 shl $2,itmp1 /* multiply by 4 bytes */
430 mov FltSave(itmp3),itmp1 /* itmp1 = saved flt register count */
455 pop xptr /* restore exception pointer */
456 mov FrameSize(itmp3),itmp2 /* get frame size */
457 add itmp2,sp /* unwind stack */
459 pop xpc /* the new xpc is return address */
460 sub $2,xpc /* subtract 2-bytes for call */
462 xor itmp3,itmp3 /* prepare a3 for handle_exception */
464 jmp L_asm_handle_exception_stack_loop
467 /* asm_wrapper_patcher *********************************************************
473 16 pointer to virtual java_objectheader
474 12 last byte of machine code (xmcode)
475 8 machine code (which is patched back later)
476 4 unresolved field reference
477 0 patcher function pointer to call
479 *******************************************************************************/
482 sub $((2+4)*4+sizestackframeinfo),sp /* create stack frame */
484 mov itmp1,(0+4)*4(sp) /* save itmp1 and itmp2 */
485 mov itmp2,(1+4)*4(sp) /* may be used by some instructions */
487 mov sp,itmp1 /* create stackframe info */
489 mov itmp1,0*4(sp) /* stackframeinfo pointer */
490 movl $0,1*4(sp) /* if pv is NULL, use findmethod */
492 add $((6+2+4)*4+sizestackframeinfo),itmp2
493 mov itmp2,2*4(sp) /* pass Java sp */
494 mov ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
495 mov itmp3,3*4(sp) /* pass ra to java function */
496 call stacktrace_create_inline_stackframeinfo
498 mov sp,itmp1 /* pass stack pointer */
499 add $((1+2+4)*4+sizestackframeinfo),itmp1 /* skip function pointer */
501 mov (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer */
502 call *itmp1 /* call the patcher function */
503 mov v0,1*4(sp) /* save return value */
505 mov sp,itmp1 /* remove stackframe info */
507 mov itmp1,0*4(sp) /* stackframeinfo pointer */
508 call stacktrace_remove_stackframeinfo
510 mov (0+4)*4(sp),itmp1 /* restore itmp1 and itmp2 */
511 mov (1+4)*4(sp),itmp2 /* may be used by some instructions */
512 mov 1*4(sp),itmp3 /* restore return value */
514 add $((5+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
515 test itmp3,itmp3 /* exception thrown? */
516 jz L_asm_wrapper_patcher_exception
517 ret /* call new patched code */
519 L_asm_wrapper_patcher_exception:
520 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
521 call builtin_asm_get_exceptionptrptr
524 lea _exceptionptr,itmp2
526 mov (itmp2),xptr /* get the exception pointer */
527 movl $0,(itmp2) /* clear the exception pointer */
529 pop xpc /* get and remove return address */
530 jmp L_asm_handle_exception
533 /************************ function asm_builtin_x2x *****************************
535 * Wrapper functions for corner cases *
537 *******************************************************************************/
568 /******************* function asm_initialize_thread_stack **********************
570 * initialized a thread stack *
571 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
573 *******************************************************************************/
575 asm_initialize_thread_stack:
576 mov 8(%esp),%eax /* (to)->stackEnd */
577 sub $36,%eax /* 4 bytes * 8 regs + 4 bytes func */
589 mov 4(%esp),%edx /* save (u1*) (func) */
592 ret /* return restorepoint in %eax */
595 /******************* function asm_perform_threadswitch *************************
597 * void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop); *
599 * performs a threadswitch *
601 *******************************************************************************/
603 asm_perform_threadswitch:
615 mov 36(%esp),%eax /* save current return address */
618 mov 40(%esp),%eax /* first argument **from */
621 mov 48(%esp),%eax /* third argument **stackTop */
624 mov 44(%esp),%eax /* second argument **to */
625 mov 0(%eax),%esp /* load new stack pointer */
631 /* skip stack pointer */
636 add $32,%esp /* leave return address on stack */
640 /********************* function asm_switchstackandcall *************************
642 * int asm_switchstackandcall (void *stack, void *func, void **stacktopsave, *
645 * Switches to a new stack, calls a function and switches back. *
646 * a0 new stack pointer *
647 * a1 function pointer *
648 * a2 pointer to variable where stack top should be stored *
649 * a3 pointer to user data, is passed to the function *
651 *******************************************************************************/
653 asm_switchstackandcall:
654 mov 4(%esp),%edx /* first argument *stack */
655 sub $8,%edx /* allocate new stack */
657 mov (%esp),%eax /* save return address on new stack */
660 mov %esp,4(%edx) /* save old stack pointer on new stack */
662 mov 12(%esp),%eax /* third argument **stacktopsave */
663 mov %esp,(%eax) /* save old stack pointer to variable */
665 mov 8(%esp),%eax /* load function pointer */
666 mov 16(%esp),%ecx /* fourth argument *p */
668 mov %edx,%esp /* switch to new stack */
671 mov %ecx,0(%esp) /* pass pointer */
672 call *%eax /* and call function */
675 mov (%esp),%edx /* load return address */
676 mov 4(%esp),%esp /* switch to old stack */
681 asm_getclassvalues_atomic:
683 mov 4(%esp),%ecx /* super */
684 mov 8(%esp),%edx /* sub */
686 mov offbaseval(%ecx),%eax
687 mov offdiffval(%ecx),%ecx
688 mov offbaseval(%edx),%edx
691 mov 16(%esp),%ebx /* out */
692 mov %eax,offcast_super_baseval(%ebx)
693 mov %ecx,offcast_super_diffval(%ebx)
694 mov %edx,offcast_sub_baseval(%ebx)
700 asm_criticalsections:
701 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
714 /* Disable exec-stacks, required for Gentoo ***********************************/
716 #if defined(__GCC__) && defined(__ELF__)
717 .section .note.GNU-stack,"",@progbits
722 * These are local overrides for various environment variables in Emacs.
723 * Please do not remove this and leave it at the end of the file, where
724 * Emacs will automagically detect them.
725 * ---------------------------------------------------------------------
728 * indent-tabs-mode: t