* doc/stack_frames.txt: Added file.
[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 4613 2006-03-15 12:04:05Z 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
46 #include "vm/jit/methodheader.h"
47
48
49         .text
50
51
52 /* exported functions and variables *******************************************/
53
54         .globl asm_md_init
55
56         .globl asm_vm_call_method
57         .globl asm_vm_call_method_int
58         .globl asm_vm_call_method_long
59         .globl asm_vm_call_method_float
60         .globl asm_vm_call_method_double
61
62         .globl asm_call_jit_compiler
63         .globl asm_handle_nat_exception
64         .globl asm_handle_exception
65
66         .globl asm_wrapper_patcher
67         .globl asm_replacement_out
68
69         .globl asm_builtin_f2i
70         .globl asm_builtin_f2l
71         .globl asm_builtin_d2i
72         .globl asm_builtin_d2l
73
74         .globl asm_perform_threadswitch
75         .globl asm_initialize_thread_stack
76         .globl asm_switchstackandcall
77         .globl asm_criticalsections
78         .globl asm_getclassvalues_atomic
79
80
81 /* asm_md_init *****************************************************************
82
83    Initialize machine dependent stuff.
84
85    See: http://www.srware.com/linux_numerics.txt
86
87    This puts the X86 FPU in 64-bit precision mode.  The default under
88    Linux is to use 80-bit mode, which produces subtle differences from
89    FreeBSD and other systems, eg, (int)(1000*atof("0.3")) is 300 in
90    64-bit mode, 299 in 80-bit mode.
91
92    Fixes: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=350729
93
94 *******************************************************************************/
95
96 asm_md_init:
97         sub     $4,sp                       /* allocate space for the FPU state   */
98         fnstcw  (sp)                        /* get the FPU state                  */
99         mov     (sp),%eax
100         and     $0xfcff,%ax                 /* remove the extended mode flag      */
101         or      $0x0200,%ax                 /* put the double mode flag           */
102         mov     %eax,(sp)                   /* store new FPU state                */
103         fldcw   (sp)                        /* setup new FPU state                */
104         add     $4,sp
105         ret
106
107
108 /********************* function asm_calljavafunction ***************************
109 *                                                                              *
110 *   This function calls a Java-method (which possibly needs compilation)       *
111 *   with up to 4 address parameters.                                           *
112 *                                                                              *
113 *   This functions calls the JIT-compiler which eventually translates the      *
114 *   method into machine code.                                                  *
115 *                                                                              *
116 *   C-prototype:                                                               *
117 *    javaobject_header *asm_vm_call_method(methodinfo *m,                      *
118 *         u4 count, u4 size, void *callblock);                                 *
119 *                                                                              *
120 *******************************************************************************/
121
122         .align  8
123
124         .long   0                           /* catch type all                     */
125         .long   calljava_xhandler2          /* handler pc                         */
126         .long   calljava_xhandler2          /* end pc                             */
127         .long   L_asm_vm_call_method        /* start pc                           */
128         .long   1                           /* extable size                       */
129         .long   0                           /* line number table start            */
130         .long   0                           /* line number table size             */
131         .long   0                           /* fltsave                            */
132         .long   0                           /* intsave                            */
133         .long   0                           /* isleaf                             */
134         .long   0                           /* IsSync                             */
135         .long   0                           /* frame size                         */
136         .long   0                           /* method pointer (pointer to name)   */
137
138 asm_vm_call_method:
139 asm_vm_call_method_int:
140 asm_vm_call_method_long:
141 asm_vm_call_method_float:
142 asm_vm_call_method_double:
143 L_asm_vm_call_method:                   /* required for PIC code              */
144         push    %ebp
145         mov     %esp,%ebp                   /* save stackptr                      */
146
147         push    %ebx                        /* save registers                     */
148         push    %esi
149         push    %edi
150
151         mov     4*4(%ebp),%eax              /* pointer to arg block (4(push)+4(return)+4+4)*/
152         mov     3*4(%ebp),%ecx              /* arg count            (4(push)+4(return)+4 */
153
154         xor     %esi,%esi                 /* clear stackframe size (MUST be       */
155                                           /* before args check, may be zero!!!)   */
156         test    %ecx,%ecx                 /* maybe we have no args                */
157         jle     calljava_copydone
158
159         mov     %ecx,%edx                 /* calculate stack size                 */
160         mov     %eax,%edi                 /* save pointer to arg block            */
161
162 calljava_calcstacksize:
163         mov     offvmargtype(%eax),%ebx
164         test    $1,%ebx                   /* two word type?                       */
165         jz      calljava_onewordtype
166         add     $4,%esi                   /* add 1 slot to stackframe size        */
167
168 calljava_onewordtype:
169         add     $4,%esi                   /* add 1 slot to stackframe size        */
170         sub     $1,%edx
171         test    %edx,%edx                 /* any args left?                       */
172         jz      calljava_setstack
173         add     $sizevmarg,%eax             /* goto next argument block           */
174         jmp     calljava_calcstacksize
175                 
176 calljava_setstack:                              
177         mov     %edi,%eax                 /* restore pointer to arg block         */
178         sub     %esi,%esp                 /* create stackframe for arguments      */
179         mov     %esp,%edi                 /* move stackpointer into temp variable */
180
181 calljava_copyloop:
182         mov     offvmargdata(%eax),%edx     /* copy 4 Byte of Argument            */
183         mov     %edx,(%edi)
184         add     $4,%edi                     /* increase sp to next argument       */
185         mov     offvmargtype(%eax),%ebx     /* type -> ebx                        */
186         test    $1,%ebx                     /* two word type?                     */
187         jz      calljava_copynext
188
189         mov     offvmargdata+4(%eax),%edx   /* copy upper 4 byte of 2 word type   */
190         mov     %edx,(%edi)                     
191         add     $4,%edi                     /* increase sp to next argument       */
192
193 calljava_copynext:              
194         sub     $1,%ecx                     /* are there any args left?           */
195         test    %ecx,%ecx
196         jle     calljava_copydone
197
198         add     $sizevmarg,%eax             /* goto next argument block           */
199         jmp     calljava_copyloop
200
201 calljava_copydone:
202         mov     2*4(%ebp),itmp1             /* move function pointer to itmp1     */
203
204         lea     L_asm_call_jit_compiler,itmp3
205         call    *itmp3                      /* call JIT compiler                  */
206
207 L_asm_vm_call_method_return:
208         add     %esi,%esp                   /* remove arg stack frame             */
209         pop     %edi                        /* restore registers                  */
210         pop     %esi
211         pop     %ebx
212         leave
213         ret
214
215 calljava_xhandler2:
216         push    xptr                        /* pass exception pointer             */
217         call    builtin_throw_exception
218         add     $4,sp
219         xor     v0,v0                       /* return NULL                        */
220         jmp     L_asm_vm_call_method_return
221
222
223 /* asm_call_jit_compiler *******************************************************
224
225    Invokes the compiler for untranslated JavaVM methods.
226
227    Register R0 contains a pointer to the method info structure (prepared
228    by createcompilerstub). Using the return address in R26 and the
229    offset in the LDA instruction or using the value in methodptr R28 the
230    patching address for storing the method address can be computed:
231
232    Method address was either loaded using
233
234    i386_mov_imm_reg(a, REG_ITMP2)                ; invokestatic/special
235    i386_call_reg(REG_ITMP2)
236
237    or
238
239    i386_mov_membase_reg(REG_SP, 0, REG_ITMP1)    ; invokevirtual/interface
240    i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)
241    i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \
242        sizeof(methodptr) * m->vftblindex, REG_ITMP1)
243    i386_call_reg(REG_ITMP1)
244
245    In the static case the method pointer can be computed using the
246    return address and the lda function following the jmp instruction.
247
248 *******************************************************************************/
249
250 asm_call_jit_compiler:
251 L_asm_call_jit_compiler:                /* required for PIC code              */
252         sub     $((4+2)*4+sizestackframeinfo),sp /* create stack frame            */
253         mov     itmp1,(4+0)*4(sp)           /* save method pointer                */
254                         
255         mov     (4+2)*4+sizestackframeinfo(sp),itmp3 /* get return address        */
256         mov     -1(itmp3),itmp1b            /* get function code                  */
257         cmp     $0xd1,itmp1b                /* called with `call *REG_ITMP2'?     */
258         jne             L_not_static_special
259
260         sub     $6,itmp3                    /* calculate address of immediate     */
261         jmp             L_call_jit_compile
262                 
263 L_not_static_special:
264         cmp     $0xd0,itmp1b                /* called with `call *REG_ITMP1'      */
265         jne             L_not_virtual_interface
266         
267         sub     $6,itmp3                    /* calculate address of offset        */
268         mov     (itmp3),itmp3               /* get offset                         */
269         add     itmp2,itmp3                 /* add base address to get method adr */
270         jmp             L_call_jit_compile
271
272 L_not_virtual_interface:
273         xor     itmp3,itmp3                 /* a call from asm_calljavafunction   */
274                 
275 L_call_jit_compile:
276         mov     itmp3,(4+1)*4(sp)           /* save address for method pointer    */
277
278         mov     sp,itmp1                    /* create stackframe info             */
279         add     $((4+2)*4),itmp1
280         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
281         movl    $0,1*4(sp)                  /* if pv is NULL, use findmethod      */
282         mov     sp,itmp2
283         add     $((1+4+2)*4+sizestackframeinfo),itmp2 /* pass java sp             */
284         mov     itmp2,2*4(sp)
285         mov     ((0+4+2)*4+sizestackframeinfo)(sp),itmp3 /* pass java ra          */
286         mov     itmp3,3*4(sp)
287         call    stacktrace_create_inline_stackframeinfo
288
289         mov     (4+0)*4(sp),itmp1           /* pass method pointer                */
290         mov     itmp1,0*4(sp)
291         call    jit_compile
292         mov     v0,(4+0)*4(sp)              /* save return value                  */
293
294         mov     sp,itmp1                    /* remove stackframe info             */
295         add     $((4+2)*4),itmp1
296         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
297         call    stacktrace_remove_stackframeinfo
298
299         mov     (4+0)*4(sp),v0              /* restore return value               */
300         mov     (4+1)*4(sp),itmp3           /* restore address for method pointer */
301
302         add     $((4+2)*4+sizestackframeinfo),sp /* remove stack frame            */
303
304         test    v0,v0                       /* check for exception                */
305         je      L_asm_call_jit_compiler_exception
306
307         test    itmp3,itmp3                 /* was this a JIT call?               */
308         je              L_call_method
309         
310         mov     v0,(itmp3)                  /* save the new method pointer        */
311
312 L_call_method:
313         jmp             *v0                         /* ...and now call the new method     */
314
315 L_asm_call_jit_compiler_exception:
316 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
317         call    builtin_asm_get_exceptionptrptr
318         mov     v0,itmp2                    /* v0 == itmp1                        */
319 #else
320         lea     _exceptionptr,itmp2
321 #endif
322         mov     (itmp2),xptr                /* get the exception pointer          */
323         movl    $0,(itmp2)                  /* clear the exception pointer        */
324
325         pop     xpc                         /* get return address                 */
326         sub     $2,xpc                      /* faulting address is ra - 2         */
327         jmp     L_asm_handle_exception
328
329
330 /* asm_handle_exception ********************************************************
331 *                                                                              *
332 *   This function handles an exception. It does not use the usual calling      *
333 *   conventions. The exception pointer is passed in REG_ITMP1 and the          *
334 *   pc from the exception raising position is passed in REG_ITMP2. It searches *
335 *   the local exception table for a handler. If no one is found, it unwinds    *
336 *   stacks and continues searching the callers.                                *
337 *                                                                              *
338 *******************************************************************************/
339
340 asm_handle_nat_exception:
341         add     $4,sp                       /* clear return address of native stub*/
342                 
343 asm_handle_exception:
344 L_asm_handle_exception:                 /* required for PIC code              */
345         sub     $((ARG_CNT+TMP_CNT)*4),sp   /* create maybe-leaf stackframe       */
346
347         SAVE_ARGUMENT_REGISTERS(0)          /* we save arg and temp registers in  */
348         SAVE_TEMPORARY_REGISTERS(ARG_CNT)   /* case this is a leaf method         */
349
350         mov     $((ARG_CNT+TMP_CNT)*4),itmp3/* prepare a3 for handle_exception    */
351         mov     $1,t0                       /* set maybe-leaf flag                */
352
353 L_asm_handle_exception_stack_loop:
354         sub     $(10*4),sp                  /* create stackframe                  */
355         mov     xptr,4*4(sp)                /* save exception pointer             */
356         mov     xpc,5*4(sp)                 /* save exception pc                  */
357         add     sp,itmp3                    /* calculate Java sp into a3...       */
358         add     $(10*4),itmp3
359         mov     itmp3,7*4(sp)               /* ...and save it                     */
360         mov     t0,8*4(sp)                  /* save maybe-leaf flag               */
361
362         mov     xpc,0*4(sp)                 /* pass exception pc                  */
363         call    codegen_findmethod
364         mov     v0,6*4(sp)                  /* save data segment pointer          */
365
366         mov     4*4(sp),itmp3               /* pass exception pointer             */
367         mov     itmp3,0*4(sp)
368         mov     5*4(sp),itmp3               /* pass exception pc                  */
369         mov     itmp3,1*4(sp)
370         mov     v0,2*4(sp)                  /* pass data segment pointer          */
371         mov     7*4(sp),itmp3               /* pass Java stack pointer            */
372         mov     itmp3,3*4(sp)
373         call    exceptions_handle_exception
374
375         test    v0,v0
376         jz      L_asm_handle_exception_not_catched
377
378         mov     v0,xpc                      /* move handlerpc into xpc            */
379         mov     4*4(sp),xptr                /* restore exception pointer          */
380         mov     8*4(sp),t0                  /* get maybe-leaf flag                */
381         add     $(10*4),sp                  /* free stackframe                    */
382
383         test    t0,t0                       /* test for maybe-leaf flag           */
384         jz      L_asm_handle_exception_no_leaf
385
386         RESTORE_ARGUMENT_REGISTERS(0)       /* if this is a leaf method, we have  */
387         RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers  */
388
389         add     $((ARG_CNT+TMP_CNT)*4),sp   /* remove maybe-leaf stackframe       */
390
391 L_asm_handle_exception_no_leaf:
392         jmp     *xpc                        /* jump to exception handler          */
393
394 L_asm_handle_exception_not_catched:
395         mov     4*4(sp),xptr                /* restore exception pointer          */
396         mov     6*4(sp),itmp3               /* restore data segment pointer       */
397         mov     8*4(sp),t0                  /* get maybe-leaf flag                */
398         add     $(10*4),sp                  /* free stackframe                    */
399
400         test    t0,t0
401         jz      L_asm_handle_exception_no_leaf_stack
402
403         add     $((ARG_CNT+TMP_CNT)*4),sp   /* remove maybe-leaf stackframe       */
404         xor     t0,t0                       /* clear the maybe-leaf flag          */
405
406 L_asm_handle_exception_no_leaf_stack:
407         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
408         add     sp,itmp2                    /* pointer to save area               */
409
410         push    xptr                        /* we are out of registers            */
411
412         mov     IntSave(itmp3),itmp1        /* itmp1 = saved int register count   */
413         test    itmp1,itmp1
414         je      noint
415
416         cmp     $1,itmp1
417         je      int1
418         cmp     $2,itmp1
419         je      int2
420
421         mov     -3*4(itmp2),s0
422 int2:   
423         mov     -2*4(itmp2),s1
424 int1:   
425         mov     -1*4(itmp2),s2
426
427         shl     $2,itmp1                    /* multiply by 4 bytes                */
428         sub     itmp1,itmp2
429                 
430 noint:
431 #if 0
432         mov     FltSave(itmp3),itmp1        /* itmp1 = saved flt register count   */
433         test    itmp1,itmp1
434         je      noflt
435
436         cmp     $1,itmp1
437         je      flt1
438         cmp     $2,itmp1
439         je      flt2
440         cmp     $3,itmp1
441         je      flt3
442                 
443         fldl    -4*8(itmp2)
444         fstp    %st(1)
445 flt3:
446         fldl    -3*8(itmp2)
447         fstp    %st(2)
448 flt2:
449         fldl    -2*8(itmp2)
450         fstp    %st(3)
451 flt1:
452         fldl    -1*8(itmp2)
453         fstp    %st(4)
454                 
455 noflt:
456 #endif
457         pop     xptr                        /* restore exception pointer          */
458         mov     FrameSize(itmp3),itmp2      /* get frame size                     */
459         add     itmp2,sp                    /* unwind stack                       */
460
461         pop     xpc                         /* the new xpc is return address      */
462         sub     $2,xpc                      /* subtract 2-bytes for call          */
463
464         xor     itmp3,itmp3                 /* prepare a3 for handle_exception    */
465
466         jmp     L_asm_handle_exception_stack_loop
467                 
468
469 /* asm_wrapper_patcher *********************************************************
470
471    XXX
472
473    Stack layout:
474      24   return address
475      20   REG_ITMP3
476      16   pointer to virtual java_objectheader
477      12   last byte of machine code (xmcode)
478       8   machine code (which is patched back later)
479       4   unresolved field reference
480       0   patcher function pointer to call
481
482 *******************************************************************************/
483
484 asm_wrapper_patcher:
485         sub     $((2+4)*4+sizestackframeinfo),sp /* create stack frame            */
486
487         mov     itmp1,(0+4)*4(sp)           /* save itmp1 and itmp2               */
488         mov     itmp2,(1+4)*4(sp)           /* may be used by some instructions   */
489
490         mov     sp,itmp1                    /* create stackframe info             */
491         add     $((2+4)*4),itmp1
492         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
493         movl    $0,1*4(sp)                  /* if pv is NULL, use findmethod      */
494         mov     sp,itmp2
495         add     $((7+2+4)*4+sizestackframeinfo),itmp2
496         mov     itmp2,2*4(sp)               /* pass Java sp                       */
497         mov     ((6+2+4)*4+sizestackframeinfo)(sp),itmp3
498         mov     itmp3,3*4(sp)               /* pass ra to java function           */
499         call    stacktrace_create_inline_stackframeinfo
500
501         mov     sp,itmp1                    /* pass stack pointer                 */
502         add     $((1+2+4)*4+sizestackframeinfo),itmp1  /* skip function pointer   */
503         mov     itmp1,0*4(sp)
504         mov     (0+2+4)*4+sizestackframeinfo(sp),itmp1 /* get function pointer    */
505         call    *itmp1                      /* call the patcher function          */
506         mov     v0,1*4(sp)                  /* save return value                  */
507
508         mov     sp,itmp1                    /* remove stackframe info             */
509         add     $((2+4)*4),itmp1
510         mov     itmp1,0*4(sp)               /* stackframeinfo pointer             */
511         call    stacktrace_remove_stackframeinfo
512
513         mov     1*4(sp),itmp3               /* restore return value               */
514         test    itmp3,itmp3                 /* exception thrown?                  */
515         jz      L_asm_wrapper_patcher_exception
516
517         mov     (0+4)*4(sp),itmp1           /* restore itmp1 and itmp2            */
518         mov     (1+4)*4(sp),itmp2           /* may be used by some instructions   */
519         mov     ((5+2+4)*4+sizestackframeinfo)(sp),itmp3
520         add     $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
521
522         ret                                 /* call new patched code              */
523
524 L_asm_wrapper_patcher_exception:
525         add     $((6+2+4)*4+sizestackframeinfo),sp /* remove stack frame, keep ra */
526
527 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
528         call    builtin_asm_get_exceptionptrptr
529         mov     v0,itmp2
530 #else
531         lea     _exceptionptr,itmp2
532 #endif
533         mov     (itmp2),xptr                /* get the exception pointer          */
534         movl    $0,(itmp2)                  /* clear the exception pointer        */
535
536         pop     xpc                         /* get and remove return address      */
537         jmp     L_asm_handle_exception
538
539
540 /* asm_replacement_out *********************************************************
541
542    This code is jumped to from the replacement-out stubs that are executed
543    when a thread reaches an activated replacement point.
544
545    The purpose of asm_replacement_out is to read out the parts of the
546    execution state that cannot be accessed from C code, store this state,
547    and then call the C function replace_me.
548
549    Stack layout:
550       0   rplpoint *    info on the replacement point that was reached
551
552 *******************************************************************************/
553
554 asm_replacement_out:
555         sub     $(sizeexecutionstate),sp    /* create stack frame                 */
556
557         mov     itmp1,(0*8+offes_regs)(sp)
558         movl    $0,(4+0*8+offes_regs)(sp)
559         mov     itmp2,(1*8+offes_regs)(sp)
560         movl    $0,(4+1*8+offes_regs)(sp)
561         mov     itmp3,(2*8+offes_regs)(sp)
562         movl    $0,(4+2*8+offes_regs)(sp)
563
564         mov     sizeexecutionstate(sp),itmp1   /* rplpoint *                         */
565     push    sp                          /* arg1: execution state              */
566     push    itmp1                       /* arg0: replacement point            */
567     call    replace_me                  /* call C function replace_me         */
568     call    abort                       /* NEVER REACHED                      */
569
570 /************************ function asm_builtin_x2x *****************************
571 *                                                                              *
572 *   Wrapper functions for corner cases                                         *
573 *                                                                              *
574 *******************************************************************************/
575
576 asm_builtin_f2i:
577         sub     $4,%esp
578         fsts    (%esp)
579         call    builtin_f2i
580         add     $4,%esp
581         ret
582
583 asm_builtin_d2i:
584         sub     $8,%esp
585         fstl    (%esp)
586         call    builtin_d2i
587         add     $8,%esp
588         ret
589
590 asm_builtin_f2l:
591         sub     $4,%esp
592         fsts    (%esp)
593         call    builtin_f2l
594         add     $4,%esp
595         ret
596
597 asm_builtin_d2l:
598         sub     $8,%esp
599         fstl    (%esp)
600         call    builtin_d2l
601         add     $8,%esp
602         ret
603
604
605 /******************* function asm_initialize_thread_stack **********************
606 *                                                                              *
607 * initialized a thread stack                                                   *
608 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
609 *                                                                              *
610 *******************************************************************************/
611
612 asm_initialize_thread_stack:
613                 mov             8(%esp),%eax            /* (to)->stackEnd                     */
614                 sub             $36,%eax                /* 4 bytes * 8 regs + 4 bytes func    */
615                                 
616                 xor             %edx,%edx
617                 mov             %edx,0(%eax)
618                 mov             %edx,4(%eax)
619                 mov             %edx,8(%eax)
620                 mov             %edx,12(%eax)
621                 mov             %edx,16(%eax)
622                 mov             %edx,20(%eax)
623                 mov     %edx,24(%eax)
624                 mov     %edx,28(%eax)
625                                 
626                 mov     4(%esp),%edx            /* save (u1*) (func)                  */
627                 mov     %edx,32(%eax)
628
629                 ret                             /* return restorepoint in %eax        */
630
631
632 /******************* function asm_perform_threadswitch *************************
633 *                                                                              *
634 *   void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop);         *
635 *                                                                              *
636 *   performs a threadswitch                                                    *
637 *                                                                              *
638 *******************************************************************************/
639
640 asm_perform_threadswitch:
641         sub     $36,%esp
642            
643         mov     %eax,0(%esp)
644         mov     %ecx,4(%esp)
645         mov     %edx,8(%esp)
646         mov     %ebx,12(%esp)
647         mov     %esp,16(%esp)
648         mov     %ebp,20(%esp)
649         mov     %esi,24(%esp)
650         mov     %edi,28(%esp)
651            
652         mov     36(%esp),%eax         /* save current return address              */
653         mov     %eax,32(%esp)
654            
655         mov     40(%esp),%eax         /* first argument **from                    */
656         mov     %esp,0(%eax)
657            
658         mov     48(%esp),%eax         /* third argument **stackTop                */
659         mov     %esp,0(%eax)
660            
661         mov     44(%esp),%eax         /* second argument **to                     */
662         mov     0(%eax),%esp          /* load new stack pointer                   */
663            
664         mov     0(%esp),%eax
665         mov     4(%esp),%ecx
666         mov     8(%esp),%edx
667         mov     12(%esp),%ebx
668                                       /* skip stack pointer                       */
669         mov     20(%esp),%ebp
670         mov     24(%esp),%esi
671         mov     28(%esp),%edi
672            
673         add     $32,%esp              /* leave return address on stack            */
674         ret
675                 
676
677 /********************* function asm_switchstackandcall *************************
678 *                                                                              *
679 *  int asm_switchstackandcall (void *stack, void *func, void **stacktopsave,   *
680 *                                      void *p);                                       *
681 *                                                                              *
682 *   Switches to a new stack, calls a function and switches back.               *
683 *       a0      new stack pointer                                              *
684 *       a1      function pointer                                               *
685 *               a2              pointer to variable where stack top should be stored           *
686 *       a3      pointer to user data, is passed to the function                *
687 *                                                                              *
688 *******************************************************************************/
689
690 asm_switchstackandcall:
691         mov     4(%esp),%edx          /* first argument *stack                    */
692         sub     $8,%edx               /* allocate new stack                       */
693
694         mov     (%esp),%eax           /* save return address on new stack         */
695         mov     %eax,(%edx)
696
697         mov     %esp,4(%edx)          /* save old stack pointer on new stack      */
698
699         mov     12(%esp),%eax         /* third argument **stacktopsave            */
700         mov     %esp,(%eax)           /* save old stack pointer to variable       */
701
702         mov     8(%esp),%eax          /* load function pointer                    */
703         mov     16(%esp),%ecx         /* fourth argument *p                       */
704         
705         mov     %edx,%esp             /* switch to new stack                      */
706
707         sub     $4,%esp
708         mov     %ecx,0(%esp)          /* pass pointer                             */
709         call    *%eax                 /* and call function                        */
710         add     $4,%esp
711
712         mov     (%esp),%edx           /* load return address                      */
713         mov     4(%esp),%esp          /* switch to old stack                      */
714         mov     %edx,(%esp)
715         ret
716
717                 
718 asm_getclassvalues_atomic:
719 _crit_restart2:
720         mov     4(%esp),%ecx        /* super */
721         mov     8(%esp),%edx        /* sub */
722 _crit_begin2:
723         mov     offbaseval(%ecx),%eax
724         mov     offdiffval(%ecx),%ecx
725         mov     offbaseval(%edx),%edx
726 _crit_end2:
727         push    %ebx
728         mov     16(%esp),%ebx      /* out */
729         mov     %eax,offcast_super_baseval(%ebx)
730         mov     %ecx,offcast_super_diffval(%ebx)
731         mov     %edx,offcast_sub_baseval(%ebx)
732         pop     %ebx
733         ret
734
735         .data
736
737 asm_criticalsections:
738 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
739 #if 0
740         .long   _crit_begin1
741         .long   _crit_end1
742         .long   _crit_restart1
743 #endif
744         .long   _crit_begin2
745         .long   _crit_end2
746         .long   _crit_restart2
747 #endif
748         .long 0
749
750
751 /* Disable exec-stacks, required for Gentoo ***********************************/
752
753 #if defined(__GCC__) && defined(__ELF__)
754         .section .note.GNU-stack,"",@progbits
755 #endif
756
757
758 /*
759  * These are local overrides for various environment variables in Emacs.
760  * Please do not remove this and leave it at the end of the file, where
761  * Emacs will automagically detect them.
762  * ---------------------------------------------------------------------
763  * Local variables:
764  * mode: asm
765  * indent-tabs-mode: t
766  * c-basic-offset: 4
767  * tab-width: 4
768  * End:
769  * vim:noexpandtab:sw=4:ts=4:
770  */