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