* src/vm/jit/i386/asmpart.S (asm_vm_call_method): Save/restore stack pointer
[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 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    Contact: cacao@cacaojvm.org
26
27    Authors: Andreas Krall
28             Reinhard Grafl
29             Christian Thalinger
30
31    Changes: Joseph Wenninger
32             Edwin Steiner
33
34    $Id: asmpart.S 4677 2006-03-22 20:59:49Z edwin $
35
36 */
37
38
39 #include "config.h"
40
41 #include "vm/jit/abi.h"
42 #include "vm/jit/i386/md-abi.h"
43 #include "vm/jit/i386/md-asm.h"
44 #include "vm/jit/i386/offsets.h"
45 #include "vm/jit/i386/arch.h"
46
47 #include "vm/jit/methodheader.h"
48
49
50         .text
51
52
53 /* exported functions and variables *******************************************/
54
55         .globl asm_md_init
56
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
63         .globl asm_call_jit_compiler
64         .globl asm_handle_nat_exception
65         .globl asm_handle_exception
66
67         .globl asm_wrapper_patcher
68
69         .globl asm_replacement_out
70         .globl asm_replacement_in
71
72         .globl asm_builtin_f2i
73         .globl asm_builtin_f2l
74         .globl asm_builtin_d2i
75         .globl asm_builtin_d2l
76
77         .globl asm_perform_threadswitch
78         .globl asm_initialize_thread_stack
79         .globl asm_switchstackandcall
80         .globl asm_criticalsections
81         .globl asm_getclassvalues_atomic
82
83
84 /* asm_md_init *****************************************************************
85
86    Initialize machine dependent stuff.
87
88    See: http://www.srware.com/linux_numerics.txt
89
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.
94
95    Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
96
97 *******************************************************************************/
98
99 asm_md_init:
100         sub     $4,sp                       /* allocate space for the FPU state   */
101         fnstcw  (sp)                        /* get the FPU state                  */
102         mov     (sp),%eax
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                */
107         add     $4,sp
108         ret
109
110
111 /********************* function asm_calljavafunction ***************************
112 *                                                                              *
113 *   This function calls a Java-method (which possibly needs compilation)       *
114 *   with up to 4 address parameters.                                           *
115 *                                                                              *
116 *   This functions calls the JIT-compiler which eventually translates the      *
117 *   method into machine code.                                                  *
118 *                                                                              *
119 *   C-prototype:                                                               *
120 *    javaobject_header *asm_vm_call_method(methodinfo *m,                      *
121 *         u4 count, u4 size, void *callblock);                                 *
122 *                                                                              *
123 *******************************************************************************/
124
125         .align  8
126
127         .long   0                           /* catch type all                     */
128         .long   calljava_xhandler2          /* handler pc                         */
129         .long   calljava_xhandler2          /* end pc                             */
130         .long   L_asm_vm_call_method        /* 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                            */
136         .long   0                           /* isleaf                             */
137         .long   0                           /* IsSync                             */
138         .long   0                           /* frame size                         */
139         .long   0                           /* method pointer (pointer to name)   */
140
141 asm_vm_call_method:
142 asm_vm_call_method_int:
143 asm_vm_call_method_long:
144 asm_vm_call_method_float:
145 asm_vm_call_method_double:
146 L_asm_vm_call_method:                   /* required for PIC code              */
147         push    bp
148         mov     sp,bp                       /* save stackptr                      */
149         sub     $(4*4),sp                   /* create stackframe                  */
150         and     $0xfffffff0,sp              /* align stack to 16-byte             */
151
152         mov     t0,0*4(sp)                  /* save registers                     */
153         mov     s1,1*4(sp)
154         mov     s2,2*4(sp)
155
156         mov     4*4(bp),itmp1               /* pointer to arg block (4(push)+4(return)+4+4)*/
157         mov     3*4(bp),itmp2               /* arg count            (4(push)+4(return)+4 */
158
159         mov     sp,s1                       /* save the stackpointer              */
160
161         test    itmp2,itmp2                 /* maybe we have no args              */
162         jle     calljava_copydone
163
164         mov     itmp2,itmp3                 /* calculate stack size               */
165         mov     itmp1,%edi                  /* save pointer to arg block          */
166
167 calljava_calcstacksize:
168         mov     offvmargtype(itmp1),t0
169         test    $1,t0                       /* two word type?                     */
170         jz      calljava_onewordtype
171
172         sub     $4,sp                       /* add 1 slot to stackframe size      */
173
174 calljava_onewordtype:
175         sub     $4,sp                       /* add 1 slot to stackframe size      */
176         sub     $1,itmp3
177         test    itmp3,itmp3                 /* any args left?                     */
178         jz      calljava_setstack
179
180         add     $sizevmarg,itmp1            /* goto next argument block           */
181         jmp     calljava_calcstacksize
182                 
183 calljava_setstack:                              
184         mov     %edi,itmp1                  /* restore pointer to arg block       */
185         and     $0xfffffff0,sp              /* align stack to 16-byte             */
186         mov     sp,itmp3                    /* initialize pointer for copying     */
187
188 calljava_copyloop:
189         mov     offvmargdata(itmp1),t0      /* get 4-bytes of argument            */
190         mov     t0,(itmp3)                  /* and store them on the stack        */
191         add     $4,itmp3                    /* increase sp to next argument       */
192         mov     offvmargtype(itmp1),t0      /* get the argument type              */
193         test    $1,t0                       /* two word type?                     */
194         jz      calljava_copynext
195
196         mov     offvmargdata+4(itmp1),t0    /* get upper 4-bytes of 2 word type   */
197         mov     t0,(itmp3)                      
198         add     $4,itmp3                    /* increase sp to next argument       */
199
200 calljava_copynext:              
201         sub     $1,itmp2                    /* are there any args left?           */
202         test    itmp2,itmp2
203         jle     calljava_copydone
204
205         add     $sizevmarg,itmp1            /* goto next argument block           */
206         jmp     calljava_copyloop
207
208 calljava_copydone:
209         mov     2*4(bp),itmp1               /* move function pointer to itmp1     */
210
211         lea     L_asm_call_jit_compiler,itmp3
212         call    *itmp3                      /* call JIT compiler                  */
213
214 L_asm_vm_call_method_return:
215         mov     s1,sp                       /* restore stackpointer               */
216
217         mov     0*4(sp),t0                  /* restore registers                  */
218         mov     1*4(sp),s1
219         mov     2*4(sp),s2
220
221         leave
222         ret
223
224 calljava_xhandler2:
225         push    xptr                        /* pass exception pointer             */
226         call    builtin_throw_exception
227         add     $4,sp
228         xor     v0,v0                       /* return NULL                        */
229         jmp     L_asm_vm_call_method_return
230
231
232 /* asm_call_jit_compiler *******************************************************
233
234    Invokes the compiler for untranslated JavaVM methods.
235
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:
240
241    Method address was either loaded using
242
243    i386_mov_imm_reg(a, REG_ITMP2)                ; invokestatic/special
244    i386_call_reg(REG_ITMP2)
245
246    or
247
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)
253
254    In the static case the method pointer can be computed using the
255    return address and the lda function following the jmp instruction.
256
257 *******************************************************************************/
258
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                */
263                         
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
268
269         sub     $6,itmp3                    /* calculate address of immediate     */
270         jmp             L_call_jit_compile
271                 
272 L_not_static_special:
273         cmp     $0xd0,itmp1b                /* called with `call *REG_ITMP1'      */
274         jne             L_not_virtual_interface
275         
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
280
281 L_not_virtual_interface:
282         xor     itmp3,itmp3                 /* a call from asm_calljavafunction   */
283                 
284 L_call_jit_compile:
285         mov     itmp3,(4+1)*4(sp)           /* save address for method pointer    */
286
287         mov     sp,itmp1                    /* create stackframe info             */
288         add     $((4+2)*4),itmp1
289         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
290         movl    $0,1*4(sp)                  /* if pv is NULL, use findmethod      */
291         mov     sp,itmp2
292         add     $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp             */
293         mov     itmp2,2*4(sp)
294         mov     ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra          */
295         mov     itmp3,3*4(sp)
296         call    stacktrace_create_inline_stackframeinfo
297
298         mov     (4+0)*4(sp),itmp1           /* pass method pointer                */
299         mov     itmp1,0*4(sp)
300         call    jit_compile
301         mov     v0,(4+0)*4(sp)              /* save return value                  */
302
303         mov     sp,itmp1                    /* remove stackframe info             */
304         add     $((4+2)*4),itmp1
305         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
306         call    stacktrace_remove_stackframeinfo
307
308         mov     (4+0)*4(sp),v0              /* restore return value               */
309         mov     (4+1)*4(sp),itmp3           /* restore address for method pointer */
310
311         add     $((4+2)*4+sizestackframeinfo),sp /* remove stack frame            */
312
313         test    v0,v0                       /* check for exception                */
314         je      L_asm_call_jit_compiler_exception
315
316         test    itmp3,itmp3                 /* was this a JIT call?               */
317         je              L_call_method
318         
319         mov     v0,(itmp3)                  /* save the new method pointer        */
320
321 L_call_method:
322         jmp             *v0                         /* ...and now call the new method     */
323
324 L_asm_call_jit_compiler_exception:
325 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
326         call    builtin_asm_get_exceptionptrptr
327         mov     v0,itmp2                    /* v0 == itmp1                        */
328 #else
329         lea     _exceptionptr,itmp2
330 #endif
331         mov     (itmp2),xptr                /* get the exception pointer          */
332         movl    $0,(itmp2)                  /* clear the exception pointer        */
333
334         pop     xpc                         /* get return address                 */
335         sub     $2,xpc                      /* faulting address is ra - 2         */
336         jmp     L_asm_handle_exception
337
338
339 /* asm_handle_exception ********************************************************
340 *                                                                              *
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.                                *
346 *                                                                              *
347 *******************************************************************************/
348
349 asm_handle_nat_exception:
350         add     $4,sp                       /* clear return address of native stub*/
351                 
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       */
355
356         SAVE_ARGUMENT_REGISTERS(0)          /* we save arg and temp registers in  */
357         SAVE_TEMPORARY_REGISTERS(ARG_CNT)   /* case this is a leaf method         */
358
359         mov     $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception    */
360         mov     $1,t0                       /* set maybe-leaf flag                */
361
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...       */
367         add     $(10*4),itmp3
368         mov     itmp3,7*4(sp)               /* ...and save it                     */
369         mov     t0,8*4(sp)                  /* save maybe-leaf flag               */
370
371         mov     xpc,0*4(sp)                 /* pass exception pc                  */
372         call    codegen_findmethod
373         mov     v0,6*4(sp)                  /* save data segment pointer          */
374
375         mov     4*4(sp),itmp3               /* pass exception pointer             */
376         mov     itmp3,0*4(sp)
377         mov     5*4(sp),itmp3               /* pass exception pc                  */
378         mov     itmp3,1*4(sp)
379         mov     v0,2*4(sp)                  /* pass data segment pointer          */
380         mov     7*4(sp),itmp3               /* pass Java stack pointer            */
381         mov     itmp3,3*4(sp)
382         call    exceptions_handle_exception
383
384         test    v0,v0
385         jz      L_asm_handle_exception_not_catched
386
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                    */
391
392         test    t0,t0                       /* test for maybe-leaf flag           */
393         jz      L_asm_handle_exception_no_leaf
394
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  */
397
398         add     $((ARG_CNT+TMP_CNT)*4),sp   /* remove maybe-leaf stackframe       */
399
400 L_asm_handle_exception_no_leaf:
401         jmp     *xpc                        /* jump to exception handler          */
402
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                    */
408
409         test    t0,t0
410         jz      L_asm_handle_exception_no_leaf_stack
411
412         add     $((ARG_CNT+TMP_CNT)*4),sp   /* remove maybe-leaf stackframe       */
413         xor     t0,t0                       /* clear the maybe-leaf flag          */
414
415 L_asm_handle_exception_no_leaf_stack:
416         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
417         add     sp,itmp2                    /* pointer to save area               */
418
419         push    xptr                        /* we are out of registers            */
420
421         mov     IntSave(itmp3),itmp1        /* itmp1 = saved int register count   */
422         test    itmp1,itmp1
423         je      noint
424
425         cmp     $1,itmp1
426         je      int1
427         cmp     $2,itmp1
428         je      int2
429
430         mov     -3*4(itmp2),s0
431 int2:   
432         mov     -2*4(itmp2),s1
433 int1:   
434         mov     -1*4(itmp2),s2
435
436         shl     $2,itmp1                    /* multiply by 4 bytes                */
437         sub     itmp1,itmp2
438                 
439 noint:
440 #if 0
441         mov     FltSave(itmp3),itmp1        /* itmp1 = saved flt register count   */
442         test    itmp1,itmp1
443         je      noflt
444
445         cmp     $1,itmp1
446         je      flt1
447         cmp     $2,itmp1
448         je      flt2
449         cmp     $3,itmp1
450         je      flt3
451                 
452         fldl    -4*8(itmp2)
453         fstp    %st(1)
454 flt3:
455         fldl    -3*8(itmp2)
456         fstp    %st(2)
457 flt2:
458         fldl    -2*8(itmp2)
459         fstp    %st(3)
460 flt1:
461         fldl    -1*8(itmp2)
462         fstp    %st(4)
463                 
464 noflt:
465 #endif
466         pop     xptr                        /* restore exception pointer          */
467         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
468         add     itmp2,sp                    /* unwind stack                       */
469
470         pop     xpc                         /* the new xpc is return address      */
471         sub     $2,xpc                      /* subtract 2-bytes for call          */
472
473         xor     itmp3,itmp3                 /* prepare a3 for handle_exception    */
474
475         jmp     L_asm_handle_exception_stack_loop
476                 
477
478 /* asm_wrapper_patcher *********************************************************
479
480    XXX
481
482    Stack layout:
483      24   return address
484      20   REG_ITMP3
485      16   pointer to virtual java_objectheader
486      12   last byte of machine code (xmcode)
487       8   machine code (which is patched back later)
488       4   unresolved field reference
489       0   patcher function pointer to call
490
491 *******************************************************************************/
492
493 asm_wrapper_patcher:
494         sub     $((2+4)*4+sizestackframeinfo),sp /* create stack frame            */
495
496         mov     itmp1,(0+4)*4(sp)           /* save itmp1 and itmp2               */
497         mov     itmp2,(1+4)*4(sp)           /* may be used by some instructions   */
498
499         mov     sp,itmp1                    /* create stackframe info             */
500         add     $((2+4)*4),itmp1
501         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
502         movl    $0,1*4(sp)                  /* if pv is NULL, use findmethod      */
503         mov     sp,itmp2
504         add     $((7+2+4)*4+sizestackframeinfo),itmp2
505         mov     itmp2,2*4(sp)               /* pass Java sp                       */
506         mov     ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
507         mov     itmp3,3*4(sp)               /* pass ra to java function           */
508         call    stacktrace_create_inline_stackframeinfo
509
510         mov     sp,itmp1                    /* pass stack pointer                 */
511         add     $((1+2+4)*4+sizestackframeinfo),itmp1  /* skip function pointer   */
512         mov     itmp1,0*4(sp)
513         mov     (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer    */
514         call    *itmp1                      /* call the patcher function          */
515         mov     v0,1*4(sp)                  /* save return value                  */
516
517         mov     sp,itmp1                    /* remove stackframe info             */
518         add     $((2+4)*4),itmp1
519         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
520         call    stacktrace_remove_stackframeinfo
521
522         mov     1*4(sp),itmp3               /* restore return value               */
523         test    itmp3,itmp3                 /* exception thrown?                  */
524         jz      L_asm_wrapper_patcher_exception
525
526         mov     (0+4)*4(sp),itmp1           /* restore itmp1 and itmp2            */
527         mov     (1+4)*4(sp),itmp2           /* may be used by some instructions   */
528         mov     ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
529         add     $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
530
531         ret                                 /* call new patched code              */
532
533 L_asm_wrapper_patcher_exception:
534         add     $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
535
536 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
537         call    builtin_asm_get_exceptionptrptr
538         mov     v0,itmp2
539 #else
540         lea     _exceptionptr,itmp2
541 #endif
542         mov     (itmp2),xptr                /* get the exception pointer          */
543         movl    $0,(itmp2)                  /* clear the exception pointer        */
544
545         pop     xpc                         /* get and remove return address      */
546         jmp     L_asm_handle_exception
547
548
549 /* asm_replacement_out *********************************************************
550
551    This code is jumped to from the replacement-out stubs that are executed
552    when a thread reaches an activated replacement point.
553
554    The purpose of asm_replacement_out is to read out the parts of the
555    execution state that cannot be accessed from C code, store this state,
556    and then call the C function replace_me.
557
558    Stack layout:
559       4                 start of stack inside method to replace
560       0   rplpoint *    info on the replacement point that was reached
561
562 *******************************************************************************/
563
564 /* some room to accomodate changes of the stack frame size during replacement */
565         /* XXX we should find a cleaner solution here */
566 #define REPLACEMENT_ROOM  512
567
568 asm_replacement_out:
569     /* create stack frame */
570         sub     $(sizeexecutionstate + REPLACEMENT_ROOM),sp
571
572         /* save registers in execution state */
573         mov     %eax,(EAX*8+offes_intregs)(sp)
574         mov     %ebx,(EBX*8+offes_intregs)(sp)
575         mov     %ecx,(ECX*8+offes_intregs)(sp)
576         mov     %edx,(EDX*8+offes_intregs)(sp)
577         mov     %esi,(ESI*8+offes_intregs)(sp)
578         mov     %edi,(EDI*8+offes_intregs)(sp)
579         mov     %ebp,(EBP*8+offes_intregs)(sp)
580         movl    $0  ,(ESP*8+offes_intregs)(sp) /* not used */
581
582 #ifndef NDEBUG
583         /* clear high 32bit */
584         movl    $0,(4+0*8+offes_intregs)(sp)
585         movl    $0,(4+1*8+offes_intregs)(sp)
586         movl    $0,(4+2*8+offes_intregs)(sp)
587         movl    $0,(4+3*8+offes_intregs)(sp)
588         movl    $0,(4+4*8+offes_intregs)(sp)
589         movl    $0,(4+5*8+offes_intregs)(sp)
590         movl    $0,(4+6*8+offes_intregs)(sp)
591         movl    $0,(4+7*8+offes_intregs)(sp)
592 #endif
593
594         /* calculate sp of method */
595         mov     sp,itmp1
596         add     $(sizeexecutionstate + REPLACEMENT_ROOM + 4),itmp1
597         mov     itmp1,(offes_sp)(sp)
598
599         /* pv must be looked up via AVL tree */
600         movl    $0,(offes_pv)(sp)
601
602         /* call replace_me */
603         mov     -4(itmp1),itmp1             /* rplpoint *                         */
604     push    sp                          /* arg1: execution state              */
605     push    itmp1                       /* arg0: replacement point            */
606     call    replace_me                  /* call C function replace_me         */
607     call    abort                       /* NEVER REACHED                      */
608
609 /* asm_replacement_in **********************************************************
610
611    This code writes the given execution state and jumps to the replacement
612    code.
613
614    This function never returns!
615
616    C prototype:
617       void asm_replacement_in(executionstate *es);
618
619 *******************************************************************************/
620
621 asm_replacement_in:
622         mov     4(sp),%ebp                  /* executionstate *es                 */
623
624         /* set new sp */
625         mov     (offes_sp)(%ebp),%esp
626         
627         /* store address of new code */
628         push    (offes_pc)(%ebp)
629         
630         /* copy registers from execution state */
631         mov     (EAX*8+offes_intregs)(%ebp),%eax
632         mov     (EBX*8+offes_intregs)(%ebp),%ebx
633         mov     (ECX*8+offes_intregs)(%ebp),%ecx
634         mov     (EDX*8+offes_intregs)(%ebp),%edx
635         mov     (ESI*8+offes_intregs)(%ebp),%esi
636         mov     (EDI*8+offes_intregs)(%ebp),%edi
637
638         mov     (EBP*8+offes_intregs)(%ebp),%ebp
639
640         /* jump to new code */
641         ret
642
643 /************************ function asm_builtin_x2x *****************************
644 *                                                                              *
645 *   Wrapper functions for corner cases                                         *
646 *                                                                              *
647 *******************************************************************************/
648
649 asm_builtin_f2i:
650         sub     $4,%esp
651         fsts    (%esp)
652         call    builtin_f2i
653         add     $4,%esp
654         ret
655
656 asm_builtin_d2i:
657         sub     $8,%esp
658         fstl    (%esp)
659         call    builtin_d2i
660         add     $8,%esp
661         ret
662
663 asm_builtin_f2l:
664         sub     $4,%esp
665         fsts    (%esp)
666         call    builtin_f2l
667         add     $4,%esp
668         ret
669
670 asm_builtin_d2l:
671         sub     $8,%esp
672         fstl    (%esp)
673         call    builtin_d2l
674         add     $8,%esp
675         ret
676
677
678 /******************* function asm_initialize_thread_stack **********************
679 *                                                                              *
680 * initialized a thread stack                                                   *
681 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
682 *                                                                              *
683 *******************************************************************************/
684
685 asm_initialize_thread_stack:
686                 mov             8(%esp),%eax            /* (to)->stackEnd                     */
687                 sub             $36,%eax                /* 4 bytes * 8 regs + 4 bytes func    */
688                                 
689                 xor             %edx,%edx
690                 mov             %edx,0(%eax)
691                 mov             %edx,4(%eax)
692                 mov             %edx,8(%eax)
693                 mov             %edx,12(%eax)
694                 mov             %edx,16(%eax)
695                 mov             %edx,20(%eax)
696                 mov     %edx,24(%eax)
697                 mov     %edx,28(%eax)
698                                 
699                 mov     4(%esp),%edx            /* save (u1*) (func)                  */
700                 mov     %edx,32(%eax)
701
702                 ret                             /* return restorepoint in %eax        */
703
704
705 /******************* function asm_perform_threadswitch *************************
706 *                                                                              *
707 *   void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop);         *
708 *                                                                              *
709 *   performs a threadswitch                                                    *
710 *                                                                              *
711 *******************************************************************************/
712
713 asm_perform_threadswitch:
714         sub     $36,%esp
715            
716         mov     %eax,0(%esp)
717         mov     %ecx,4(%esp)
718         mov     %edx,8(%esp)
719         mov     %ebx,12(%esp)
720         mov     %esp,16(%esp)
721         mov     %ebp,20(%esp)
722         mov     %esi,24(%esp)
723         mov     %edi,28(%esp)
724            
725         mov     36(%esp),%eax         /* save current return address              */
726         mov     %eax,32(%esp)
727            
728         mov     40(%esp),%eax         /* first argument **from                    */
729         mov     %esp,0(%eax)
730            
731         mov     48(%esp),%eax         /* third argument **stackTop                */
732         mov     %esp,0(%eax)
733            
734         mov     44(%esp),%eax         /* second argument **to                     */
735         mov     0(%eax),%esp          /* load new stack pointer                   */
736            
737         mov     0(%esp),%eax
738         mov     4(%esp),%ecx
739         mov     8(%esp),%edx
740         mov     12(%esp),%ebx
741                                       /* skip stack pointer                       */
742         mov     20(%esp),%ebp
743         mov     24(%esp),%esi
744         mov     28(%esp),%edi
745            
746         add     $32,%esp              /* leave return address on stack            */
747         ret
748                 
749
750 /********************* function asm_switchstackandcall *************************
751 *                                                                              *
752 *  int asm_switchstackandcall (void *stack, void *func, void **stacktopsave,   *
753 *                                      void *p);                                       *
754 *                                                                              *
755 *   Switches to a new stack, calls a function and switches back.               *
756 *       a0      new stack pointer                                              *
757 *       a1      function pointer                                               *
758 *               a2              pointer to variable where stack top should be stored           *
759 *       a3      pointer to user data, is passed to the function                *
760 *                                                                              *
761 *******************************************************************************/
762
763 asm_switchstackandcall:
764         mov     4(%esp),%edx          /* first argument *stack                    */
765         sub     $8,%edx               /* allocate new stack                       */
766
767         mov     (%esp),%eax           /* save return address on new stack         */
768         mov     %eax,(%edx)
769
770         mov     %esp,4(%edx)          /* save old stack pointer on new stack      */
771
772         mov     12(%esp),%eax         /* third argument **stacktopsave            */
773         mov     %esp,(%eax)           /* save old stack pointer to variable       */
774
775         mov     8(%esp),%eax          /* load function pointer                    */
776         mov     16(%esp),%ecx         /* fourth argument *p                       */
777         
778         mov     %edx,%esp             /* switch to new stack                      */
779
780         sub     $4,%esp
781         mov     %ecx,0(%esp)          /* pass pointer                             */
782         call    *%eax                 /* and call function                        */
783         add     $4,%esp
784
785         mov     (%esp),%edx           /* load return address                      */
786         mov     4(%esp),%esp          /* switch to old stack                      */
787         mov     %edx,(%esp)
788         ret
789
790                 
791 asm_getclassvalues_atomic:
792 _crit_restart2:
793         mov     4(%esp),%ecx        /* super */
794         mov     8(%esp),%edx        /* sub */
795 _crit_begin2:
796         mov     offbaseval(%ecx),%eax
797         mov     offdiffval(%ecx),%ecx
798         mov     offbaseval(%edx),%edx
799 _crit_end2:
800         push    %ebx
801         mov     16(%esp),%ebx      /* out */
802         mov     %eax,offcast_super_baseval(%ebx)
803         mov     %ecx,offcast_super_diffval(%ebx)
804         mov     %edx,offcast_sub_baseval(%ebx)
805         pop     %ebx
806         ret
807
808         .data
809
810 asm_criticalsections:
811 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
812 #if 0
813         .long   _crit_begin1
814         .long   _crit_end1
815         .long   _crit_restart1
816 #endif
817         .long   _crit_begin2
818         .long   _crit_end2
819         .long   _crit_restart2
820 #endif
821         .long 0
822
823
824 /* Disable exec-stacks, required for Gentoo ***********************************/
825
826 #if defined(__GCC__) && defined(__ELF__)
827         .section .note.GNU-stack,"",@progbits
828 #endif
829
830
831 /*
832  * These are local overrides for various environment variables in Emacs.
833  * Please do not remove this and leave it at the end of the file, where
834  * Emacs will automagically detect them.
835  * ---------------------------------------------------------------------
836  * Local variables:
837  * mode: asm
838  * indent-tabs-mode: t
839  * c-basic-offset: 4
840  * tab-width: 4
841  * End:
842  * vim:noexpandtab:sw=4:ts=4:
843  */