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