dc19dd6ae90a14e0332a856eeabf63e8cab45a1b
[cacao.git] / src / vm / jit / i386 / asmpart.S
1 /* src/vm/jit/i386/asmpart.S - Java-C interface functions for i386
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include "md-asm.h"
31
32 #include "vm/jit/i386/arch.h"
33 #include "vm/jit/i386/md-abi.h"
34
35 #include "vm/jit/abi-asm.h"
36 #include "vm/jit/methodheader.h"
37
38
39         .text
40
41
42 /* export functions ***********************************************************/
43
44         .globl asm_md_init
45
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
53
54         .globl asm_call_jit_compiler
55         .globl asm_handle_nat_exception
56         .globl asm_handle_exception
57
58         .globl asm_abstractmethoderror
59
60 #if defined(ENABLE_REPLACEMENT)
61         .globl asm_replacement_out
62         .globl asm_replacement_in
63 #endif
64
65         .globl asm_builtin_f2i
66         .globl asm_builtin_f2l
67         .globl asm_builtin_d2i
68         .globl asm_builtin_d2l
69
70         .globl asm_compare_and_swap
71         .globl asm_memory_barrier
72
73         .globl asm_get_cycle_count
74
75
76 /* asm_md_init *****************************************************************
77
78    Initialize machine dependent stuff.
79
80    See: http://www.srware.com/linux_numerics.txt
81
82    This puts the X86 FPU in 64-bit precision mode.  The default under
83    Linux is to use 80-bit mode, which produces subtle differences from
84    FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
85    64-bit mode, 299 in 80-bit mode.
86
87    Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
88
89 *******************************************************************************/
90
91 asm_md_init:
92         sub     $4,sp                       /* allocate space for the FPU state   */
93         fnstcw  (sp)                        /* get the FPU state                  */
94         mov     (sp),%eax
95         and     $0xfcff,%ax                 /* remove the extended mode flag      */
96         or      $0x0200,%ax                 /* put the double mode flag           */
97         mov     %eax,(sp)                   /* store new FPU state                */
98         fldcw   (sp)                        /* setup new FPU state                */
99         add     $4,sp
100         ret
101
102
103 /********************* function asm_calljavafunction ***************************
104 *                                                                              *
105 *   This function calls a Java-method (which possibly needs compilation)       *
106 *   with up to 4 address parameters.                                           *
107 *                                                                              *
108 *   This functions calls the JIT-compiler which eventually translates the      *
109 *   method into machine code.                                                  *
110 *                                                                              *
111 *   C-prototype:                                                               *
112 *    javaobject_header *asm_vm_call_method(methodinfo *m,                      *
113 *         u4 count, u4 size, void *callblock);                                 *
114 *                                                                              *
115 *******************************************************************************/
116
117         .align  8
118
119         .long   0                           /* catch type all                     */
120         .long   0                           /* handler pc                         */
121         .long   0                           /* end pc                             */
122         .long   0                           /* start pc                           */
123         .long   1                           /* extable size                       */
124         .long   0                           /* line number table start            */
125         .long   0                           /* line number table size             */
126         .long   0                           /* fltsave                            */
127         .long   0                           /* intsave                            */
128         .long   0                           /* isleaf                             */
129         .long   0                           /* IsSync                             */
130         .long   0                           /* frame size                         */
131         .long   0                           /* codeinfo pointer                   */
132
133 asm_vm_call_method:
134 asm_vm_call_method_int:
135 asm_vm_call_method_long:
136 asm_vm_call_method_float:
137 asm_vm_call_method_double:
138         push    bp
139         mov     sp,bp                       /* save stackptr                      */
140         sub     $(4*4),sp                   /* create stackframe                  */
141         and     $0xfffffff0,sp              /* align stack to 16-byte             */
142
143         mov     t0,0*4(sp)                  /* save registers                     */
144         mov     s1,1*4(sp)
145         mov     s2,2*4(sp)
146
147         mov     sp,s1                       /* save stack pointer                 */
148
149         mov     3*4(bp),t0                  /* address of data structure          */
150         mov     4*4(bp),itmp1               /* number of stack arguments          */
151
152         cmp     $0,itmp1
153         je      L_asm_vm_call_method_stack_copy_done
154
155         mov     itmp1,itmp2
156         add     $1,itmp2                    /* keep stack 16-byte aligned         */
157         and     $0xfffffffe,itmp2
158         shl     $3,itmp2                    /* calculate stack size               */
159         sub     itmp2,sp                    /* create stack frame                 */
160         mov     sp,itmp2                    /* temporary stack pointer            */
161
162 L_asm_vm_call_method_stack_copy_loop:
163         mov     0(t0),itmp3                 /* load argument                      */
164         mov     itmp3,0(itmp2)              /* store argument on stack            */
165         mov     4(t0),itmp3
166         mov     itmp3,4(itmp2)
167
168         sub     $1,itmp1                    /* subtract 1 argument                */
169         add     $8,t0                       /* set address of next argument       */
170         add     $8,itmp2                    /* increase SP                        */
171
172         cmp     $0,itmp1
173         jg      L_asm_vm_call_method_stack_copy_loop
174
175 L_asm_vm_call_method_stack_copy_done:
176         lea     (2*4-256)(bp),mptr          /* We subtract 256 to force the next  */
177                                             /* move instruction to have a 32-bit  */
178                                             /* offset.                            */
179
180         mov     (0*4+256)(mptr),itmp3       /* method call as in Java             */
181         call    *itmp3                      /* call JIT compiler                  */
182
183 L_asm_vm_call_method_return:
184         mov     s1,sp                       /* restore stackpointer               */
185
186         mov     0*4(sp),t0                  /* restore registers                  */
187         mov     1*4(sp),s1
188         mov     2*4(sp),s2
189
190         leave
191         ret
192
193 asm_vm_call_method_exception_handler:
194         push    xptr                        /* pass exception pointer             */
195         call    builtin_throw_exception
196         add     $4,sp
197 asm_vm_call_method_end:
198         jmp     L_asm_vm_call_method_return
199
200
201 /* asm_call_jit_compiler *******************************************************
202
203    Invokes the compiler for untranslated JavaVM methods.
204
205    Register R0 contains a pointer to the method info structure (prepared
206    by createcompilerstub). Using the return address in R26 and the
207    offset in the LDA instruction or using the value in methodptr R28 the
208    patching address for storing the method address can be computed:
209
210    Method address was either loaded using
211
212    i386_mov_imm_reg(a, REG_ITMP2)                ; invokestatic/special
213    i386_call_reg(REG_ITMP2)
214
215    or
216
217    i386_mov_membase_reg(REG_SP, 0, REG_ITMP1)    ; invokevirtual/interface
218    i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
219    i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
220        sizeof(methodptr) * m->vftblindex, REG_ITMP1)
221    i386_call_reg(REG_ITMP1)
222
223    In the static case the method pointer can be computed using the
224    return address and the lda function following the jmp instruction.
225
226 *******************************************************************************/
227
228 asm_call_jit_compiler:
229 L_asm_call_jit_compiler:                /* required for PIC code              */
230         sub     $(4*4),sp                   /* keep stack 16-byte aligned         */
231
232         mov     itmp1,0*4(sp)               /* pass methodinfo pointer            */
233         mov     mptr,1*4(sp)                /* pass method pointer                */
234         mov     sp,itmp2                    /* pass java sp                       */
235         add     $((1+4)*4),itmp2
236         mov     itmp2,2*4(sp)
237         mov     4*4(sp),itmp3               /* pass java ra                       */
238         mov     itmp3,3*4(sp)
239         call    jit_asm_compile
240
241         add     $(4*4),sp                   /* remove stack frame                 */
242
243         test    v0,v0                       /* check for exception                */
244         je      L_asm_call_jit_compiler_exception
245
246         jmp             *v0                         /* ...and now call the new method     */
247
248 L_asm_call_jit_compiler_exception:
249         call    exceptions_get_and_clear_exception
250                                             /* v0 == xptr                         */
251         pop     xpc                         /* get return address                 */
252         sub     $2,xpc                      /* faulting address is ra - 2         */
253         jmp     L_asm_handle_exception
254
255
256 /* asm_handle_exception ********************************************************
257 *                                                                              *
258 *   This function handles an exception. It does not use the usual calling      *
259 *   conventions. The exception pointer is passed in REG_ITMP1 and the          *
260 *   pc from the exception raising position is passed in REG_ITMP2. It searches *
261 *   the local exception table for a handler. If no one is found, it unwinds    *
262 *   stacks and continues searching the callers.                                *
263 *                                                                              *
264 *******************************************************************************/
265
266 asm_handle_nat_exception:
267         add     $4,sp                       /* clear return address of native stub*/
268                 
269 asm_handle_exception:
270 L_asm_handle_exception:                 /* required for PIC code              */
271         sub     $((ARG_CNT+TMP_CNT+3)*4),sp /* keep stack 16-byte aligned         */
272
273         SAVE_ARGUMENT_REGISTERS(0)          /* we save arg and temp registers in  */
274         SAVE_TEMPORARY_REGISTERS(ARG_CNT)   /* case this is a leaf method         */
275
276         mov     $((ARG_CNT+TMP_CNT+3)*4),itmp3 /* prepare a3 for handle_exception */
277         mov     $1,t0                       /* set maybe-leaf flag                */
278
279 L_asm_handle_exception_stack_loop:
280         sub     $(12*4),sp                  /* keep stack 16-byte aligned         */
281         mov     xptr,4*4(sp)                /* save exception pointer             */
282         mov     xpc,5*4(sp)                 /* save exception pc                  */
283         add     sp,itmp3                    /* calculate Java sp into a3...       */
284         add     $(12*4),itmp3
285         mov     itmp3,7*4(sp)               /* ...and save it                     */
286         mov     t0,8*4(sp)                  /* save maybe-leaf flag               */
287
288         mov     xpc,0*4(sp)                 /* pass exception pc                  */
289         call    codegen_get_pv_from_pc
290         mov     v0,6*4(sp)                  /* save data segment pointer          */
291
292         mov     4*4(sp),itmp3               /* pass exception pointer             */
293         mov     itmp3,0*4(sp)
294         mov     5*4(sp),itmp3               /* pass exception pc                  */
295         mov     itmp3,1*4(sp)
296         mov     v0,2*4(sp)                  /* pass data segment pointer          */
297         mov     7*4(sp),itmp3               /* pass Java stack pointer            */
298         mov     itmp3,3*4(sp)
299         call    exceptions_handle_exception
300
301         test    v0,v0
302         jz      L_asm_handle_exception_not_catched
303
304         mov     v0,xpc                      /* move handlerpc into xpc            */
305         mov     4*4(sp),xptr                /* restore exception pointer          */
306         mov     8*4(sp),t0                  /* get maybe-leaf flag                */
307         add     $(12*4),sp                  /* free stackframe                    */
308
309         test    t0,t0                       /* test for maybe-leaf flag           */
310         jz      L_asm_handle_exception_no_leaf
311
312         RESTORE_ARGUMENT_REGISTERS(0)       /* if this is a leaf method, we have  */
313         RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers  */
314
315         add     $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe       */
316
317 L_asm_handle_exception_no_leaf:
318         jmp     *xpc                        /* jump to exception handler          */
319
320 L_asm_handle_exception_not_catched:
321         mov     4*4(sp),xptr                /* restore exception pointer          */
322         mov     6*4(sp),itmp3               /* restore data segment pointer       */
323         mov     8*4(sp),t0                  /* get maybe-leaf flag                */
324         add     $(12*4),sp                  /* free stackframe                    */
325
326         test    t0,t0
327         jz      L_asm_handle_exception_no_leaf_stack
328
329         add     $((ARG_CNT+TMP_CNT+3)*4),sp /* remove maybe-leaf stackframe       */
330         xor     t0,t0                       /* clear the maybe-leaf flag          */
331
332 L_asm_handle_exception_no_leaf_stack:
333         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
334         add     sp,itmp2                    /* pointer to save area               */
335
336         push    xptr                        /* we are out of registers            */
337
338         mov     IntSave(itmp3),itmp1        /* itmp1 = saved int register count   */
339         test    itmp1,itmp1
340         je      noint
341
342         cmp     $1,itmp1
343         je      int1
344         cmp     $2,itmp1
345         je      int2
346
347         mov     -3*8(itmp2),s0
348 int2:   
349         mov     -2*8(itmp2),s1
350 int1:   
351         mov     -1*8(itmp2),s2
352
353         shl     $2,itmp1                    /* multiply by 4 bytes                */
354         sub     itmp1,itmp2
355                 
356 noint:
357 #if 0
358         mov     FltSave(itmp3),itmp1        /* itmp1 = saved flt register count   */
359         test    itmp1,itmp1
360         je      noflt
361
362         cmp     $1,itmp1
363         je      flt1
364         cmp     $2,itmp1
365         je      flt2
366         cmp     $3,itmp1
367         je      flt3
368                 
369         fldl    -4*8(itmp2)
370         fstp    %st(1)
371 flt3:
372         fldl    -3*8(itmp2)
373         fstp    %st(2)
374 flt2:
375         fldl    -2*8(itmp2)
376         fstp    %st(3)
377 flt1:
378         fldl    -1*8(itmp2)
379         fstp    %st(4)
380                 
381 noflt:
382 #endif
383         pop     xptr                        /* restore exception pointer          */
384         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
385         add     itmp2,sp                    /* unwind stack                       */
386
387         pop     xpc                         /* the new xpc is return address      */
388         sub     $2,xpc                      /* subtract 2-bytes for call          */
389
390         xor     itmp3,itmp3                 /* prepare a3 for handle_exception    */
391
392         jmp     L_asm_handle_exception_stack_loop
393                 
394
395 /* asm_abstractmethoderror *****************************************************
396
397    Creates and throws an AbstractMethodError.
398
399 *******************************************************************************/
400
401 asm_abstractmethoderror:
402         sub     $(3*4),sp                   /* keep stack 16-byte aligned         */
403         mov     sp,itmp1                    /* pass java sp                       */
404         add     $((1+3)*4),itmp1
405         mov     itmp1,0*4(sp)
406         mov     3*4(sp),itmp2               /* pass exception address             */
407         sub     $2,itmp2
408         mov     itmp2,1*4(sp)
409         call    exceptions_asm_new_abstractmethoderror
410                                             /* exception pointer is return value  */
411         add     $(3*4),sp                   /* remove stack frame                 */
412
413         pop     xpc                         /* get exception address              */
414         sub     $2,xpc                      /* exception address is ra - 2        */
415         jmp     L_asm_handle_exception
416
417
418 #if defined(ENABLE_REPLACEMENT)
419
420 /* asm_replacement_out *********************************************************
421
422    This code is jumped to from the replacement-out stubs that are executed
423    when a thread reaches an activated replacement point.
424
425    The purpose of asm_replacement_out is to read out the parts of the
426    execution state that cannot be accessed from C code, store this state,
427    and then call the C function replace_me.
428
429    Stack layout:
430       4                 start of stack inside method to replace
431       0   rplpoint *    info on the replacement point that was reached
432
433 *******************************************************************************/
434
435 /* some room to accomodate changes of the stack frame size during replacement */
436         /* XXX we should find a cleaner solution here */
437 #define REPLACEMENT_ROOM  512
438
439 asm_replacement_out:
440     /* create stack frame */
441         sub     $(sizeexecutionstate + REPLACEMENT_ROOM),sp
442
443         /* save registers in execution state */
444         mov     %eax,(EAX*4+offes_intregs)(sp)
445         mov     %ebx,(EBX*4+offes_intregs)(sp)
446         mov     %ecx,(ECX*4+offes_intregs)(sp)
447         mov     %edx,(EDX*4+offes_intregs)(sp)
448         mov     %esi,(ESI*4+offes_intregs)(sp)
449         mov     %edi,(EDI*4+offes_intregs)(sp)
450         mov     %ebp,(EBP*4+offes_intregs)(sp)
451         movl    $0  ,(ESP*4+offes_intregs)(sp) /* not used */
452
453         /* calculate sp of method */
454         mov     sp,itmp1
455         add     $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
456         mov     itmp1,(offes_sp)(sp)
457
458         /* pv must be looked up via AVL tree */
459         movl    $0,(offes_pv)(sp)
460
461         /* call replace_me */
462         mov     -4(itmp1),itmp1             /* rplpoint *                         */
463     push    sp                          /* arg1: execution state              */
464     push    itmp1                       /* arg0: replacement point            */
465     call    replace_me                  /* call C function replace_me         */
466
467
468 /* asm_replacement_in **********************************************************
469
470    This code writes the given execution state and jumps to the replacement
471    code.
472
473    This function never returns!
474
475    C prototype:
476       void asm_replacement_in(executionstate *es, replace_safestack_t *st);
477
478 *******************************************************************************/
479
480 asm_replacement_in:
481         /* get arguments */
482         mov     8(sp),%esi                  /* replace_safestack_t *st            */
483         mov     4(sp),%ebp                  /* executionstate *es == safe stack   */
484
485         /* switch to the safe stack and build a stack frame */
486         mov     %ebp,sp
487         sub             $(1*4),sp
488
489         /* call replace_build_execution_state(st) */
490         mov             %esi,(0*4)(sp)
491         call    replace_build_execution_state
492
493         /* set new sp */
494         mov     (offes_sp)(%ebp),sp
495
496         /* push address of new code */
497         push    (offes_pc)(%ebp)
498
499         /* allocate an executionstate_t on the stack */
500         sub             $(sizeexecutionstate),sp
501
502         /* call replace_free_safestack(st,& of allocated executionstate_t) */
503         push    sp   /* tmpes */
504         push    %esi /* st    */
505         call    replace_free_safestack
506         add     $(2*4),sp
507
508         /* copy registers from execution state */
509         mov     (EAX*4+offes_intregs)(sp),%eax
510         mov     (EBX*4+offes_intregs)(sp),%ebx
511         mov     (ECX*4+offes_intregs)(sp),%ecx
512         mov     (EDX*4+offes_intregs)(sp),%edx
513         mov     (ESI*4+offes_intregs)(sp),%esi
514         mov     (EDI*4+offes_intregs)(sp),%edi
515         mov     (EBP*4+offes_intregs)(sp),%ebp
516
517         /* pop the execution state off the stack */
518         add             $(sizeexecutionstate),sp
519
520         /* jump to new code, hold your thumbs! ;) */
521         ret
522
523 #endif /* defined(ENABLE_REPLACEMENT) */
524
525
526 /************************ function asm_builtin_x2x *****************************
527 *                                                                              *
528 *   Wrapper functions for corner cases                                         *
529 *                                                                              *
530 *******************************************************************************/
531
532 asm_builtin_f2i:
533         sub     $(3*4),%esp
534         fsts    (%esp)
535         call    builtin_f2i
536         add     $(3*4),%esp
537         ret
538
539 asm_builtin_d2i:
540         sub     $(3*4),%esp
541         fstl    (%esp)
542         call    builtin_d2i
543         add     $(3*4),%esp
544         ret
545
546 asm_builtin_f2l:
547         sub     $(3*4),%esp
548         fsts    (%esp)
549         call    builtin_f2l
550         add     $(3*4),%esp
551         ret
552
553 asm_builtin_d2l:
554         sub     $(3*4),%esp
555         fstl    (%esp)
556         call    builtin_d2l
557         add     $(3*4),%esp
558         ret
559
560
561 /* asm_compare_and_swap ********************************************************
562
563    Does an atomic compare and swap.  Required for the lock
564    implementation.
565
566    Atomically do the following: Check if the location still contains
567    `oldval`. If so, replace it by `newval` and return `oldval`.
568
569    RETURN VALUE:
570        the old value at *p
571
572    long compare_and_swap(volatile long *p, long oldval, long newval);
573
574 *******************************************************************************/
575
576 asm_compare_and_swap:
577         mov     1*4(sp),%ecx            /* load p into a register                 */
578         mov     2*4(sp),%eax            /* load oldval into return register       */
579         mov     3*4(sp),%edx            /* load newval into a register            */
580         lock; cmpxchgl %edx,0(%ecx)
581         ret
582
583
584 /* asm_memory_barrier **********************************************************
585
586    A memory barrier for the Java Memory Model.
587
588 *******************************************************************************/
589
590 asm_memory_barrier:
591         lock; add $0,0(sp)
592         ret
593
594                 
595 /* asm_get_cycle_count *********************************************************
596
597    Get the current time-stamp counter from the CPU.
598
599 *******************************************************************************/
600
601 asm_get_cycle_count:
602         rdtsc
603         ret
604
605
606 /* disable exec-stacks ********************************************************/
607
608 #if defined(__linux__) && defined(__ELF__)
609         .section .note.GNU-stack,"",%progbits
610 #endif
611
612
613 /*
614  * These are local overrides for various environment variables in Emacs.
615  * Please do not remove this and leave it at the end of the file, where
616  * Emacs will automagically detect them.
617  * ---------------------------------------------------------------------
618  * Local variables:
619  * mode: asm
620  * indent-tabs-mode: t
621  * c-basic-offset: 4
622  * tab-width: 4
623  * End:
624  * vim:noexpandtab:sw=4:ts=4:
625  */