9555bc1d274e75f07a4f9594b99f4adaa30785fe
[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 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Andreas Krall
28             Reinhard Grafl
29             Christian Thalinger
30
31    Changes: Joseph Wenninger
32
33    $Id: asmpart.S 2374 2005-04-25 14:13:56Z twisti $
34
35 */
36
37
38 #include "config.h"
39 #include "vm/jit/i386/offsets.h"
40 #include "vm/jit/i386/asmoffsets.h"
41
42
43 /* define it like the risc way */
44
45 #define v0       %eax
46
47 #define itmp1    %eax
48 #define itmp2    %ecx
49 #define itmp3    %edx
50
51 #define itmp1b   %al
52 #define itmp2b   %cl
53 #define itmp3b   %dl
54
55 #define xptr     itmp1
56 #define xpc      itmp2
57
58
59         .text
60
61
62 /********************* exported functions and variables ***********************/
63
64         .globl asm_calljavafunction
65         .globl asm_calljavafunction_int
66
67         .globl asm_calljavafunction2
68         .globl asm_calljavafunction2int
69         .globl asm_calljavafunction2long
70         .globl asm_calljavafunction2float
71         .globl asm_calljavafunction2double
72
73         .globl asm_call_jit_compiler
74         .globl asm_handle_builtin_exception
75         .globl asm_handle_nat_exception
76         .globl asm_handle_exception
77
78         .globl asm_wrapper_patcher
79
80         .globl asm_builtin_checkarraycast
81         .globl asm_builtin_aastore
82
83         .globl asm_builtin_ldiv
84         .globl asm_builtin_lrem
85
86         .globl asm_builtin_f2i
87         .globl asm_builtin_f2l
88         .globl asm_builtin_d2i
89         .globl asm_builtin_d2l
90
91         .globl asm_perform_threadswitch
92         .globl asm_initialize_thread_stack
93         .globl asm_switchstackandcall
94         .globl asm_getcallingmethod
95         .globl asm_criticalsections
96         .globl asm_getclassvalues_atomic
97
98         .globl asm_throw_and_handle_exception
99         .globl asm_throw_and_handle_hardware_arithmetic_exception
100
101         .globl asm_prepare_native_stackinfo
102         .globl asm_remove_native_stackinfo
103
104
105 /********************* function asm_calljavafunction ***************************
106 *                                                                              *
107 *   This function calls a Java-method (which possibly needs compilation)       *
108 *   with up to 4 address parameters.                                           *
109 *                                                                              *
110 *   This functions calls the JIT-compiler which eventually translates the      *
111 *   method into machine code.                                                  *
112 *                                                                              *
113 *   C-prototype:                                                               *
114 *    javaobject_header *asm_calljavamethod (methodinfo *m,                     *
115 *         void *arg1, void *arg2, void *arg3, void *arg4);                     *
116 *                                                                              *
117 *******************************************************************************/
118
119 call_name:
120         .align  8
121
122         .long   0                         /* catch type all                       */
123         .long   calljava_xhandler         /* handler pc                           */
124         .long   calljava_xhandler         /* end pc                               */
125         .long   asm_calljavafunction      /* start pc                             */
126         .long   1                         /* extable size                         */
127         .long   0                         /* line number table  start             */
128         .long   0                         /* line number table  size              */
129         .long   0                         /* fltsave                              */
130         .long   0                         /* intsave                              */
131         .long   0                         /* isleaf                               */
132         .long   0                         /* IsSync                               */
133         .long   32                        /* frame size                           */
134         .long   0                         /* method pointer (pointer to name)     */
135
136 asm_calljavafunction:
137 asm_calljavafunction_int:
138         push    %ebp                      /* allocate stack space                 */
139         mov     %esp, %ebp
140
141         push    %ebx                      /* save registers                       */
142         push    %esi
143         push    %edi
144
145
146         sub             $16,%esp                                        /* 4 adress parameters * 4 Bytes */
147         mov     24(%ebp),%eax                           /* copy adress parameters to new block */
148         mov     %eax,12(%esp)
149                 
150         mov     20(%ebp),%eax
151         mov     %eax,8(%esp)
152
153         mov     16(%ebp),%eax
154         mov     %eax,4(%esp)
155
156         mov     12(%ebp),%eax
157         mov     %eax,(%esp)
158                 
159         mov     8(%ebp),%eax              /* move function pointer to %eax        */
160
161         lea     asm_call_jit_compiler,%edx 
162         call    *%edx                     /* call JIT compiler                    */
163
164         add     $16,%esp
165         pop     %edi                      /* restore registers                    */
166         pop     %esi
167         pop     %ebx
168         leave
169         ret
170
171 calljava_xhandler:
172         push    %eax                      /* pass exception pointer               */
173         call    builtin_throw_exception
174         add     $4,%esp
175
176         add     $16,%esp
177         pop     %edi                      /* restore registers                    */
178         pop     %esi
179         pop     %ebx
180         leave
181         xor     %eax,%eax                 /* return NULL                          */
182         ret
183
184
185 /********************* function asm_calljavafunction ***************************
186 *                                                                              *
187 *   This function calls a Java-method (which possibly needs compilation)       *
188 *   with up to 4 address parameters.                                           *
189 *                                                                              *
190 *   This functions calls the JIT-compiler which eventually translates the      *
191 *   method into machine code.                                                  *
192 *                                                                              *
193 *   C-prototype:                                                               *
194 *    javaobject_header *asm_calljavafunction2(methodinfo *m,                   *
195 *         u4 count, u4 size, void *callblock);                                 *
196 *                                                                              *
197 *******************************************************************************/
198
199 call_name2:
200         .align  8
201
202         .long   0                         /* catch type all                       */
203         .long   calljava_xhandler2        /* handler pc                           */
204         .long   calljava_xhandler2        /* end pc                               */
205         .long   asm_calljavafunction2     /* start pc                             */
206         .long   1                         /* extable size                         */
207         .long   0                         /* line number table start              */
208         .long   0                         /* line number table size               */
209         .long   0                         /* fltsave                              */
210         .long   0                         /* intsave                              */
211         .long   0                         /* isleaf                               */
212         .long   0                         /* IsSync                               */
213         .long   32                        /* frame size                           */
214         .long   0                         /* method pointer (pointer to name)     */
215
216 asm_calljavafunction2:
217 asm_calljavafunction2int:
218 asm_calljavafunction2long:
219 asm_calljavafunction2float:
220 asm_calljavafunction2double:
221         push    %ebp
222         mov     %esp,%ebp                 /* save stackptr                        */
223
224         push    %ebx                      /* save registers                       */
225         push    %esi
226         push    %edi
227
228         mov     20(%ebp),%eax             /* pointer to arg block (4(push)+4(return)+4+4+4)*/
229         mov     12(%ebp),%ecx             /* arg count            (4(push)+4(return)+4     */
230         test    %ecx,%ecx                 /* maybe we have no args                */
231         jle     calljava_copydone
232
233                 mov             %ecx,%edx                        /* calculate stack size                 */
234                 xor             %esi,%esi
235                 mov             %eax,%edi                        /* save pointer to arg block */
236 calljava_calcstacksize:
237                 mov             offjniitemtype(%eax),%ebx
238                 test    $1,%ebx                                 /* Two Word Type? */
239                 jz              calljava_onewordtype
240                 add             $4,%esi
241 calljava_onewordtype:
242                 add             $4,%esi
243                 sub             $1,%edx
244                 test    %edx,%edx                               /* any args left ?*/
245                 jz              calljava_setstack
246                 add     $sizejniblock,%eax      /* goto next argument block             */
247                 jmp             calljava_calcstacksize
248                 
249 calljava_setstack:                              
250                 mov             %edi,%eax                        /* restore pointer to arg block */
251         sub     %esi,%esp                 /* stack frame for arguments            */
252         mov     %esp,%edi
253
254 calljava_copyloop:
255             mov     offjniitem(%eax),%edx   /* copy 4 Byte of Argument */
256             mov     %edx,(%edi)
257                 add             $4,%edi                                 /* increase sp to next argument         */
258                 mov             offjniitemtype(%eax),%ebx /* type -> ebx */
259                 test    $1,%ebx                                 /* Two Word Type? */
260                 jz              calljava_copynext
261             mov     offjniitem+4(%eax),%edx /* copy upper 4 Byte of 2 Word Type */  
262                 mov     %edx,(%edi)                     
263                 add             $4,%edi                                 /* increase sp to next argument         */
264 calljava_copynext:              
265         sub     $1,%ecx                   /* are there any args left?             */
266         test    %ecx,%ecx
267         jle     calljava_copydone
268
269         add     $sizejniblock,%eax        /* goto next argument block             */
270         jmp     calljava_copyloop
271
272 calljava_copydone:
273         mov     8(%ebp),%eax              /* move function pointer to %eax        */
274
275         lea     asm_call_jit_compiler,%edx 
276         call    *%edx                     /* call JIT compiler                    */
277         
278 calljava_return2:
279         add     %esi,%esp                 /* remove arg stack frame               */
280         pop     %edi                      /* restore registers                    */
281         pop     %esi
282         pop     %ebx
283         leave
284         ret
285
286 calljava_xhandler2:
287         push    %eax                      /* pass exception pointer               */
288         call    builtin_throw_exception
289         add     $4,%esp
290     
291         add     %esi,%esp                 /* remove arg stack frame               */
292         pop     %edi                      /* restore registers                    */
293         pop     %esi
294         pop     %ebx
295         leave
296         xor     %eax,%eax                 /* return NULL                          */
297         ret
298
299
300 /****************** function asm_call_jit_compiler *****************************
301 *                                                                              *
302 *   invokes the compiler for untranslated JavaVM methods.                      *
303 *                                                                              *
304 *   Register R0 contains a pointer to the method info structure (prepared      *
305 *   by createcompilerstub). Using the return address in R26 and the            *
306 *   offset in the LDA instruction or using the value in methodptr R28 the      *
307 *   patching address for storing the method address can be computed:           *
308 *                                                                              *
309 *   method address was either loaded using                                     *
310 *                                                                              *
311 *   i386_mov_imm_reg(a, REG_ITMP2)                ; invokestatic/special       *
312 *   i386_call_reg(REG_ITMP2)                                                   *
313 *                                                                              *
314 *   or                                                                         *
315 *                                                                              *
316 *   i386_mov_membase_reg(REG_SP, 0, REG_ITMP1)    ; invokevirtual/interface    *
317 *   i386_mov_membase_reg(REG_ITMP1, OFFSET(, vftbl), REG_ITMP2)                *
318 *   i386_mov_membase_reg(REG_ITMP2, OFFSET(vftbl, table[0]) + \                *
319 *       sizeof(methodptr) * m->vftblindex, REG_ITMP1)                          *
320 *   i386_call_reg(REG_ITMP1)                                                   *
321 *                                                                              *
322 *   in the static case the method pointer can be computed using the            *
323 *   return address and the lda function following the jmp instruction          *
324 *                                                                              *
325 *******************************************************************************/
326
327 asm_call_jit_compiler:
328         push    %ebx                /* save register                              */
329     push    %ebp
330                         
331         mov     2*4(%esp),%ebp      /* get return address (2 push)                */
332         mov     -1(%ebp),%bl        /* get function code                          */
333         cmp     $0xd1,%bl           /* called with `call *REG_ITMP2' (%ecx)?      */
334         jne             L_not_static_special
335
336         sub     $6,%ebp             /* calculate address of immediate             */
337         jmp             L_call_jit_compile
338                 
339 L_not_static_special:
340         cmp     $0xd0,%bl           /* called with `call *REG_ITMP1' (%eax)       */
341         jne             L_not_virtual_interface
342         
343         sub     $6,%ebp             /* calculate address of offset                */
344         mov     (%ebp),%ebp         /* get offset                                 */
345         add     itmp2,%ebp          /* add base address to get method address     */
346         jmp             L_call_jit_compile
347
348 L_not_virtual_interface:        /* a call from asm_calljavafunction           */
349         xor     %ebp,%ebp
350                 
351 L_call_jit_compile:
352         push    %ebp                /* save address for method pointer            */
353
354         push    %eax                /* push methodpointer on stack                */
355         call    jit_compile
356         add     $4,%esp
357
358         pop     %ebp                /* restore address for method pointer         */
359
360         test    %eax,%eax           /* check for exception                        */
361         je      L_asm_call_jit_compiler_exception
362
363         test    %ebp,%ebp           /* is address == 0 (asm_calljavafunction)     */
364         je              L_call_method
365         
366         mov     %eax,(%ebp)         /* and now save the new pointer               */
367
368 L_call_method:
369         pop     %ebp                /* restore registers                          */
370         pop     %ebx
371                 
372         jmp             *%eax               /* ...and now call the new method             */
373
374 L_asm_call_jit_compiler_exception:
375         pop     %ebp                /* restore registers                          */
376         pop     %ebx
377
378 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
379         call    builtin_asm_get_exceptionptrptr
380         mov     %eax,%ecx
381 #else
382         lea     _exceptionptr,%ecx
383 #endif
384         mov     (%ecx),%eax         /* get the exception pointer                  */
385         movl    $0,(%ecx)           /* clear the exception pointer                */
386
387         pop     %ecx                /* delete return address                      */
388         sub     $2,%ecx             /* faulting address is return adress - 2      */
389
390 L_refillinStacktrace:               /*a compilation error should cause a stacktrace
391                                     which starts at the method call, which caused
392                                     the compilation of the new function. Until this
393                                     point the trace is invalid anyways, since it is
394                                     not complete. Compared to other runtimes it will
395                                     not be correct either, since we report eg class
396                                     not found errors too early, since we always
397                                     compile methods completely. The native info
398                                     should be moved around the jit call to get
399                                     a more compliant trace for the "exception in
400                                     initializer" case*/
401         push %ecx               /* store fault adress */
402         push %eax               /* temporarily save exception pointer*/
403         push $0                 /* internal function */
404         call builtin_asm_get_stackframeinfo
405         push %eax       /* save location of thread specific stack info head pointer */
406         mov (%eax),%ecx /* save old value of pointer*/
407         push %ecx
408         mov %esp,(%eax) /*store pointer to this structure*/
409         mov 12(%esp),%eax  /* get the exception pointer again*/
410         movl $0,12(%esp) /*java stack begins just above structure*/
411         push $0 /*used for the jni_callblock structure*/
412         push %eax /*save eax for later */
413         /* get fillInStackTrace method*/
414         push utf_void__java_lang_Throwable
415         push utf_fillInStackTrace
416         mov offobjvftbl(%eax),%ecx
417         mov offclass(%ecx),%eax
418         push %eax
419         call class_resolvemethod
420         add $12,%esp
421         push $0
422         push $4 /*TYPE_ADR*/
423         push %esp
424         push $sizejniblock
425         push $1
426         push %eax
427         call asm_calljavafunction2
428         add $24,%esp
429
430         /*remove native stack info */
431         mov 8(%esp),%ecx
432         mov 12(%esp),%eax
433         mov %ecx,(%eax)
434         mov (%esp),%eax
435         add $24,%esp
436         pop %ecx
437
438         
439         jmp     asm_handle_exception
440
441
442 /********************* function asm_handle_exception ***************************
443 *                                                                              *
444 *   This function handles an exception. It does not use the usual calling      *
445 *   conventions. The exception pointer is passed in REG_ITMP1 and the          *
446 *   pc from the exception raising position is passed in REG_ITMP2. It searches *
447 *   the local exception table for a handler. If no one is found, it unwinds    *
448 *   stacks and continues searching the callers.                                *
449 *                                                                              *
450 *   void asm_handle_exception (exceptionptr, exceptionpc);                     *
451 *                                                                              *
452 *******************************************************************************/
453
454 asm_handle_nat_exception:
455                 add     $4,%esp                                         /* clear return address of native stub */
456                 
457 asm_handle_exception:
458 asm_handle_exception_loop:
459                 push    %ebp
460                 mov     %esp,%ebp
461         
462                 push    %eax                                            /* save exception pointer         */
463                 push    %ecx                        /* save exception pc              */
464
465                 call    codegen_findmethod          /* get the data segment ptr       */
466                 mov     %eax,%edx
467                         
468                 mov     -4(%ebp),%eax
469                 mov     -8(%ebp),%ecx               /* could be changed in findmethod */
470
471                 push    %edx                                            /* save data segment pointer      */
472                 push    %ebx
473                 push    %esi
474                 push    %edi
475                 
476 ex_stack_loop:
477                 sub     $20,%esp
478                 mov     %eax,(%esp)                                     /* exception pointer              */
479                 mov     MethodPointer(%edx),%eax        /* method pointer                 */
480                 mov     %eax,4(%esp)
481                 mov     %ecx,8(%esp)                            /* exception pc                   */
482                 movl    $0,12(%esp)                 /* line number                    */
483                 movl    $1,16(%esp)                                     /* set no unwind flag             */
484                 call    builtin_trace_exception
485                 add     $20,%esp
486                 mov     -12(%ebp),%esi                          /* %esi = data segment pointer    */
487                 mov     ExTableSize(%esi),%ecx          /* %ecx = exception table size    */
488                 test    %ecx,%ecx                                       /* if empty table skip            */
489                 je      empty_table
490
491                 lea             ExTableStart(%esi),%edi         /* %edi = start of exception table*/
492                 mov     -4(%ebp),%eax               /* get xptr                       */
493                 
494 ex_table_loop:
495                 mov     -8(%ebp),%edx                           /* get xpc                        */
496
497                 mov     ExStartPC(%edi),%ebx            /* %ebx = exception start pc      */
498                 cmp     %edx,%ebx                                       /* %ebx = (startpc <= xpc)        */
499                 jg      ex_table_cont                           /* if (false) continue            */
500                 mov     ExEndPC(%edi),%ebx                      /* %ebx = exception end pc        */
501                 cmp     %ebx,%edx                                       /* %ebx = (xpc < endpc)           */
502                 jge     ex_table_cont                           /* if (false) continue            */
503                 mov     ExCatchType(%edi),%ebx          /* arg1 = exception catch type    */
504                 test    %ebx,%ebx                                       /* NULL catches everything        */
505                 je      ex_handle_it
506
507         cmpl    $0,offclassloaded(%ebx)     /* check if class is loaded           */
508         jne     L_class_loaded
509
510         sub     $3*4,%esp
511         mov     %eax,1*4(%esp)              /* save not callee saved regs         */
512         mov     %ecx,2*4(%esp)
513
514         mov     %ebx,0*4(%esp)              /* exception class is argument        */
515         call    load_class_bootstrap
516
517         mov     0*4(%esp),%ebx
518         mov     1*4(%esp),%eax
519         mov     2*4(%esp),%ecx
520         add     $3*4,%esp
521
522 L_class_loaded:
523         cmpl    $0,offclasslinked(%ebx)
524         jne     L_class_linked
525
526         sub     $3*4,%esp
527         mov     %eax,1*4(%esp)              /* save not callee saved regs         */
528         mov     %ecx,2*4(%esp)
529
530         mov     %ebx,0*4(%esp)              /* exception class is argument        */
531         call    link_class
532
533         mov     0*4(%esp),%ebx
534         mov     1*4(%esp),%eax
535         mov     2*4(%esp),%ecx
536         add     $3*4,%esp
537
538 L_class_linked:
539 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
540         push    %ebx
541
542 _crit_restart1:
543         mov     0(%esp),%ebx
544 #endif
545                 
546 _crit_begin1:
547         mov     offobjvftbl(%eax),%esi          /* %esi = vftblptr(xptr)              */
548         mov     offclassvftbl(%ebx),%ebx    /* %ebx = vftblptr(catchtype) class (not obj) */
549         mov     offbaseval(%esi),%esi           /* %esi = baseval(xptr)               */
550         mov     offbaseval(%ebx),%edx           /* %edx = baseval(catchtype)          */
551         mov     offdiffval(%ebx),%ebx           /* %ebx = diffval(catchtype)          */
552 _crit_end1:
553         sub     %edx,%esi                                       /* %esi = baseval(xptr) - baseval(catchtype) */
554
555 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
556         add     $4,%esp
557 #endif
558         
559         cmp     %ebx,%esi                                       /* xptr is instanceof catchtype       */
560         ja      ex_table_cont
561                 
562 ex_handle_it:
563                 mov     ExHandlerPC(%edi),%edx
564                 
565                 pop     %edi                        /* restore registers              */
566                 pop     %esi
567                 pop     %ebx
568         add     $8,%esp                     /* suck %ecx, %edx                */
569         pop     %eax                        /* restore xptr                   */
570
571                 leave
572                 jmp             *%edx                       /* jump to exception handler      */
573
574 ex_table_cont:
575                 lea     ExEntrySize(%edi),%edi
576                 dec     %ecx
577                 test    %ecx,%ecx
578                 jg      ex_table_loop
579                 
580 empty_table:
581         pop     %edi
582         pop     %esi
583         pop     %ebx
584         pop     %edx                        /* restore data segment pointer   */
585         pop     %ecx
586         pop     %eax
587         pop     %ebp
588
589         push    %eax                        /* save exception pointer         */
590         
591 ex_already_cleared:
592                 mov     IsSync(%edx),%eax                       /* %eax = SyncOffset              */
593                 test    %eax,%eax                                       /* if zero no monitorexit         */
594                 je      no_monitor_exit
595
596 #if defined(USE_THREADS)
597         add     %esp,%eax
598         mov     (%eax),%eax               /* we have the xptr on the stack (+4-4=0)  */
599         push    %edx                        /* save regs                      */
600         push    %eax
601                 call    builtin_monitorexit
602                 add     $4,%esp
603         pop     %edx                        /* restore regs                   */
604 #endif
605
606 no_monitor_exit:
607         mov     %esp,%eax
608         add     FrameSize(%edx),%eax        /* %eax = frame size              */
609         add     $4,%eax                     /* we have the xptr on the stack  */
610         
611                 mov     IntSave(%edx),%ecx          /* %ecx = saved int register count*/
612                 test    %ecx,%ecx
613                 je      noint
614                 cmp     $1,%ecx
615                 je      int1
616                 cmp     $2,%ecx
617                 je      int2
618                 cmp     $3,%ecx
619                 je      int3
620
621 int4:   
622                 mov     -16(%eax),%ebx
623
624 int3:   
625                 mov     -12(%eax),%ebp
626
627 int2:   
628                 mov     -8(%eax),%esi
629
630 int1:   
631                 mov     -4(%eax),%edi
632
633                 shl     $2,%ecx                                         /* multiply by 4 bytes             */
634                 sub     %ecx,%eax
635                 
636 noint:
637                 mov     FltSave(%edx),%ecx                      /* %ecx = saved flt register count */
638                 test    %ecx,%ecx
639                 je      noflt
640                 cmp     $1,%ecx
641                 je      flt1
642                 cmp     $2,%ecx
643                 je      flt2
644                 cmp     $3,%ecx
645                 je      flt3
646                 
647 flt4:   
648                 fldl    -32(%eax)
649                 fstp    %st(1)
650
651 flt3:   
652                 fldl    -24(%eax)
653                 fstp    %st(2)
654                 
655 flt2:   
656                 fldl    -16(%eax)
657                 fstp    %st(3)
658                 
659 flt1:   
660                 fldl    -8(%eax)
661                 fstp    %st(4)
662                 
663 noflt:
664         pop     %eax                        /* restore exception pointer      */
665         
666         mov     FrameSize(%edx),%ecx        /* %ecx = frame size              */
667         add     %ecx,%esp                   /* unwind stack                   */
668         
669                 pop     %ecx                        /* the new xpc is return address  */
670                 sub     $2,%ecx                                         /* -2 -> call */
671                 
672                 jmp             asm_handle_exception_loop
673                 
674
675 /* asm_wrapper_patcher *********************************************************
676
677    XXX
678
679    Stack layout:
680      16   return address
681      12   last byte of machine code (xmcode)
682       8   machine code (which is patched back later)
683       4   unresolved field reference
684       0   patcher function pointer to call
685
686 *******************************************************************************/
687
688 asm_wrapper_patcher:
689         sub     $(2*4),%esp                 /* create stack frame                 */
690
691         mov     itmp1,0*4(%esp)             /* save itmp1 and itmp2               */
692         mov     itmp2,1*4(%esp)             /* may be used by some instructions   */
693
694 #if 0
695         /* 3*4 bytes */
696         mov     3*4(%esp),itmp1             /* return adress into java code       */
697         mov     %esp,itmp2                  /* begin of java stack frame          */
698         add     $(3*4),itmp2
699         push    itmp1
700         push    itmp2
701         pushl   $0                          /* internal (invisible) method        */
702         call    asm_prepare_native_stackinfo /* puts additional 2 *4 bytes of
703                                                 data onto the stack */
704 #endif
705
706         mov     %esp,itmp1                  /* pass stack pointer                 */
707         add     $(3*4),itmp1                /* also skip patcher function pointer */
708         push    itmp1
709         mov     3*4(%esp),itmp1             /* get function pointer from stack    */
710         call    *itmp1                      /* call the patcher function          */
711         add     $4,%esp
712         mov     v0,itmp3                    /* save return value                  */
713
714 #if 0
715         call    asm_remove_native_stackinfo  /* removes 4* 4 bytes and leaves ret
716                                                  into java machine code on stack  */
717         add     $4,%esp                   /* ret address no longer needed, is still
718                                                 on stack a few bytes above */
719 #endif
720
721         mov     0*4(%esp),itmp1             /* restore itmp1 and itmp2            */
722         mov     1*4(%esp),itmp2             /* may be used by some instructions   */
723
724         add     $((4+2)*4),%esp             /* remove stack frame, keep ra        */
725         test    itmp3,itmp3                 /* exception thrown?                  */
726         jz      L_asm_wrapper_patcher_exception
727         ret                                 /* call new patched code              */
728
729 L_asm_wrapper_patcher_exception:
730 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
731         call    builtin_asm_get_exceptionptrptr
732         mov     v0,itmp2
733 #else
734         lea     _exceptionptr,itmp2
735 #endif
736         mov     (itmp2),xptr                /* get the exception pointer          */
737         movl    $0,(itmp2)                  /* clear the exception pointer        */
738
739         pop     xpc                         /* get and remove return address      */
740         jmp     asm_handle_exception
741
742
743 /************************ function asm_builtin_ldiv ****************************
744 *                                                                              *
745 *   Does null check and calls ldiv or throws an exception                      *
746 *                                                                              *
747 *******************************************************************************/
748
749 asm_builtin_ldiv:
750         mov     12(%esp),%eax
751         or      16(%esp),%eax
752         test    %eax,%eax                   /* if (null) throw exception          */
753         je      nb_ldiv
754
755         jmp     builtin_ldiv
756
757 nb_ldiv:
758         pop %ecx
759         sub $2,%ecx
760         jmp asm_throw_and_handle_hardware_arithmetic_exception
761 #if 0
762         push    string_java_lang_ArithmeticException_message
763         push    string_java_lang_ArithmeticException
764         call    new_exception_message
765         add     $(2*4),%esp
766         
767         pop     %ecx                        /* delete return address              */
768         sub     $2,%ecx                     /* faulting address is return adress - 2 */
769         jmp     asm_handle_exception
770 #endif                          
771
772 /************************ function asm_builtin_lrem ****************************
773 *                                                                              *
774 *   Does null check and calls lrem or throws an exception                      *
775 *                                                                              *
776 *******************************************************************************/
777
778 asm_builtin_lrem:
779         mov     12(%esp),%eax
780         or      16(%esp),%eax
781         test    %eax,%eax                   /* if (null) throw exception          */
782         je      nb_lrem
783
784         jmp     builtin_lrem
785
786 nb_lrem:
787         pop %ecx
788         sub $2,%ecx
789         jmp asm_throw_and_handle_hardware_arithmetic_exception
790 #if 0
791         push    string_java_lang_ArithmeticException_message
792         push    string_java_lang_ArithmeticException
793         call    new_exception_message
794         add     $(2*4),%esp
795
796         pop     %ecx                        /* delete return address              */
797         sub     $2,%ecx                     /* faulting address is return adress - 2 */
798         jmp     asm_handle_exception
799 #endif          
800
801 /************************ function asm_builtin_x2x *****************************
802 *                                                                              *
803 *   Wrapper functions for corner cases                                         *
804 *                                                                              *
805 *******************************************************************************/
806
807 asm_builtin_f2i:
808         sub     $4,%esp
809         fsts    (%esp)
810         call    builtin_f2i
811         add     $4,%esp
812         ret
813
814 asm_builtin_d2i:
815         sub     $8,%esp
816         fstl    (%esp)
817         call    builtin_d2i
818         add     $8,%esp
819         ret
820
821 asm_builtin_f2l:
822         sub     $4,%esp
823         fsts    (%esp)
824         call    builtin_f2l
825         add     $4,%esp
826         ret
827
828 asm_builtin_d2l:
829         sub     $8,%esp
830         fstl    (%esp)
831         call    builtin_d2l
832         add     $8,%esp
833         ret
834
835
836 /******************* function asm_builtin_checkarraycast ***********************
837 *                                                                              *
838 *   Does the cast check and eventually throws an exception                     *
839 *                                                                              *
840 *******************************************************************************/
841
842 asm_builtin_checkarraycast:
843         sub             $8,%esp                     /* build stack frame (2 * 4 bytes)    */
844
845         mov             12(%esp),%eax               /* first param:     8 (frame) + 4 (return)*/
846         mov             %eax,(%esp)                 /* save object pointer                */
847
848         mov             16(%esp),%eax                           /* second param:        8 (frame) + 4 (return) + 4*/
849         mov             %eax,4(%esp)
850
851         call    builtin_checkarraycast      /* builtin_checkarraycast             */
852
853         test    %eax,%eax                   /* if (false) throw exception         */
854         je              nb_carray_throw
855
856         mov             12(%esp),%eax               /* return object pointer              */
857         add             $8,%esp
858         ret
859
860 nb_carray_throw:
861         add $8,%esp
862         mov string_java_lang_ClassCastException,%eax
863         pop %ecx
864         sub $2,%ecx
865         jmp asm_throw_and_handle_exception
866 #if 0
867         push    string_java_lang_ClassCastException
868         call    new_exception
869         add     $(1*4),%esp
870         
871         add             $8,%esp
872         
873         pop             %ecx                        /* delete return address              */
874         sub             $2,%ecx                     /* faulting address is return adress - 2 */
875         jmp             asm_handle_exception
876 #endif
877
878                 
879 /******************* function asm_builtin_aastore ******************************
880 *                                                                              *
881 *   Does the cast check and eventually throws an exception                     *
882 * void asm_builtin_aastore(java_objectarray *a, s4 index, java_objectheader *o)*
883 *******************************************************************************/
884
885 asm_builtin_aastore:
886         sub     $12,%esp                    /* build stack frame (3 * 4 bytes)    */
887
888         mov     16(%esp),%eax               /* 12 (frame) + 4 (return)            */
889         test    %eax,%eax                   /* if null pointer throw exception    */
890         je      nb_aastore_null
891
892         mov     offarraysize(%eax),%edx     /* load size                          */
893         mov     20(%esp),%ecx               /* index  (12 + 4 + 4)                 */
894         cmp     %edx,%ecx                   /* do bound check                     */
895         jae     nb_aastore_bound            /* if out of bounds throw exception   */
896
897         shl     $2,%ecx                     /* index * 4                          */
898         add     %eax,%ecx                   /* add index * 4 to arrayref          */
899            
900         mov     %ecx,8(%esp)                /* save store position                */
901            
902         mov     16(%esp),%eax               /* 12 (frame) + 4 (return)            */
903         mov     %eax,(%esp)
904            
905         mov     24(%esp),%eax               /* object is second argument (12+4+4+4) */
906         mov     %eax,4(%esp)
907         
908         call    builtin_canstore            /* builtin_canstore(arrayref,object)  */
909
910         test    %eax,%eax                   /* if (false) throw exception         */
911         je      nb_aastore_store
912
913         mov     24(%esp),%eax
914         mov     8(%esp),%ecx
915         mov     %eax,offobjarrdata(%ecx)    /* store objectptr in array           */
916         
917         add     $12,%esp
918         ret
919
920 nb_aastore_null:
921         add $12,%esp
922         mov string_java_lang_NullPointerException,%eax
923         pop %ecx
924         sub $2,%ecx
925         jmp asm_throw_and_handle_exception
926
927 #if 0
928         push    string_java_lang_NullPointerException
929         call    new_exception
930         add     $(1*4),%esp
931         
932         add     $12,%esp
933         pop     %ecx                        /* delete return address              */
934         sub     $2,%ecx                     /* faulting address is return adress - 2 */
935         jmp             asm_handle_exception
936 #endif
937 nb_aastore_bound:
938         add     $12,%esp
939         mov         %ecx,%eax                    /* itmp2 contains array index         */
940         pushl   $0  /*directly below return adress*/
941         pushl   $0  /*internal (invisible) method*/
942         call    asm_prepare_native_stackinfo /* puts 2*4 bytes onto stack*/
943
944         push    %eax
945         call    new_arrayindexoutofboundsexception
946         add     $(1*4),%esp
947
948         call    asm_remove_native_stackinfo /*return adress is the first on stack again*/
949
950         pop     %ecx                        /* delete return address              */
951         sub     $2,%ecx                     /* faulting address is return adress - 2 */
952         jmp     asm_handle_exception
953                 
954 nb_aastore_store:
955         add     $12,%esp
956
957         mov string_java_lang_ArrayStoreException,%eax
958         pop %ecx
959         sub $2,%ecx
960         jmp asm_throw_and_handle_exception
961
962 #if 0
963         push    string_java_lang_ArrayStoreException
964         call    new_exception
965         add     $(1*4),%esp
966         
967         add     $12,%esp
968         pop     %ecx                        /* delete return address              */
969         sub     $2,%ecx                     /* faulting address is return adress - 2 */
970         jmp     asm_handle_exception
971 #endif
972
973
974 /******************* function asm_initialize_thread_stack **********************
975 *                                                                              *
976 * initialized a thread stack                                                   *
977 * (to)->restorePoint = asm_initialize_thread_stack((u1*)(func), (to)->stackEnd)*
978 *                                                                              *
979 *******************************************************************************/
980
981 asm_initialize_thread_stack:
982                 mov             8(%esp),%eax            /* (to)->stackEnd                     */
983                 sub             $36,%eax                /* 4 bytes * 8 regs + 4 bytes func    */
984                                 
985                 xor             %edx,%edx
986                 mov             %edx,0(%eax)
987                 mov             %edx,4(%eax)
988                 mov             %edx,8(%eax)
989                 mov             %edx,12(%eax)
990                 mov             %edx,16(%eax)
991                 mov             %edx,20(%eax)
992                 mov     %edx,24(%eax)
993                 mov     %edx,28(%eax)
994                                 
995                 mov     4(%esp),%edx            /* save (u1*) (func)                  */
996                 mov     %edx,32(%eax)
997
998                 ret                             /* return restorepoint in %eax        */
999
1000
1001 /******************* function asm_perform_threadswitch *************************
1002 *                                                                              *
1003 *   void asm_perform_threadswitch (u1 **from, u1 **to, u1 **stackTop);         *
1004 *                                                                              *
1005 *   performs a threadswitch                                                    *
1006 *                                                                              *
1007 *******************************************************************************/
1008
1009 asm_perform_threadswitch:
1010         sub     $36,%esp
1011            
1012         mov     %eax,0(%esp)
1013         mov     %ecx,4(%esp)
1014         mov     %edx,8(%esp)
1015         mov     %ebx,12(%esp)
1016         mov     %esp,16(%esp)
1017         mov     %ebp,20(%esp)
1018         mov     %esi,24(%esp)
1019         mov     %edi,28(%esp)
1020            
1021         mov     36(%esp),%eax         /* save current return address              */
1022         mov     %eax,32(%esp)
1023            
1024         mov     40(%esp),%eax         /* first argument **from                    */
1025         mov     %esp,0(%eax)
1026            
1027         mov     48(%esp),%eax         /* third argument **stackTop                */
1028         mov     %esp,0(%eax)
1029            
1030         mov     44(%esp),%eax         /* second argument **to                     */
1031         mov     0(%eax),%esp          /* load new stack pointer                   */
1032            
1033         mov     0(%esp),%eax
1034         mov     4(%esp),%ecx
1035         mov     8(%esp),%edx
1036         mov     12(%esp),%ebx
1037                                       /* skip stack pointer                       */
1038         mov     20(%esp),%ebp
1039         mov     24(%esp),%esi
1040         mov     28(%esp),%edi
1041            
1042         add     $32,%esp              /* leave return address on stack            */
1043         ret
1044                 
1045
1046 /********************* function asm_switchstackandcall *************************
1047 *                                                                              *
1048 *  int asm_switchstackandcall (void *stack, void *func, void **stacktopsave,   *
1049 *                                      void *p);                                       *
1050 *                                                                              *
1051 *   Switches to a new stack, calls a function and switches back.               *
1052 *       a0      new stack pointer                                              *
1053 *       a1      function pointer                                               *
1054 *               a2              pointer to variable where stack top should be stored           *
1055 *       a3      pointer to user data, is passed to the function                *
1056 *                                                                              *
1057 *******************************************************************************/
1058
1059 asm_switchstackandcall:
1060         mov     4(%esp),%edx          /* first argument *stack                    */
1061         sub     $8,%edx               /* allocate new stack                       */
1062
1063         mov     (%esp),%eax           /* save return address on new stack         */
1064         mov     %eax,(%edx)
1065
1066         mov     %esp,4(%edx)          /* save old stack pointer on new stack      */
1067
1068         mov     12(%esp),%eax         /* third argument **stacktopsave            */
1069         mov     %esp,(%eax)           /* save old stack pointer to variable       */
1070
1071         mov     8(%esp),%eax          /* load function pointer                    */
1072         mov     16(%esp),%ecx         /* fourth argument *p                       */
1073         
1074         mov     %edx,%esp             /* switch to new stack                      */
1075
1076         sub     $4,%esp
1077         mov     %ecx,0(%esp)          /* pass pointer                             */
1078         call    *%eax                 /* and call function                        */
1079         add     $4,%esp
1080
1081         mov     (%esp),%edx           /* load return address                      */
1082         mov     4(%esp),%esp          /* switch to old stack                      */
1083         mov     %edx,(%esp)
1084         ret
1085
1086                 
1087 asm_throw_and_handle_exception:
1088         push %ecx
1089         pushl $0 /* the pushed XPC is directly below the java frame*/
1090         pushl $0
1091         call asm_prepare_native_stackinfo /* be aware of the stack effect and calling convention explained below*/
1092         
1093         push %eax
1094         call new_exception
1095         add $4,%esp   /*remove parameter*/
1096
1097         call asm_remove_native_stackinfo /* be aware of the stack effect and calling convention explained below*/
1098
1099         pop %ecx
1100         jmp asm_handle_exception
1101         ret /*should never be reached */
1102
1103 asm_throw_and_handle_hardware_arithmetic_exception:
1104         
1105         push %ecx
1106         pushl $0 /* the pushed XPC is directly below the java frame*/
1107         pushl $0
1108         call asm_prepare_native_stackinfo /* be aware of the stack effect and calling convention explained below*/
1109         
1110         mov string_java_lang_ArithmeticException_message,%eax
1111         push %eax
1112         mov string_java_lang_ArithmeticException,%eax
1113         push %eax
1114
1115         call new_exception_message
1116         add $8,%esp /*remove parameters */
1117
1118         call asm_remove_native_stackinfo /* be aware of the stack effect and calling convention explained below*/
1119
1120         pop %ecx
1121         jmp asm_handle_exception
1122         ret /*should never be reached */
1123
1124 asm_builtin_new2:
1125 /*optimize a littlebit */
1126                 mov %esp,%eax
1127 /*DEBUG*/
1128 /*              push %eax
1129                 call i386_native_stub_debug
1130                 pop %eax */
1131                 
1132                 movl 4(%esp),%eax
1133                 mov     offclassinit(%eax),%ecx     /* get initialized flag           */
1134                 test    %ecx,%ecx
1135                 jnz             L_builtin_new_noinit
1136
1137                 mov 4(%esp),%eax /* class pointer, is kept during the asm_prepare... calls */
1138
1139                 /* 2 *4 bytes, the return adress is used directy */
1140                 pushl $0  /* the structure is placed directly below the java stackframe*/
1141                 pushl $0  /* builtin (invisible) method */
1142                 call  asm_prepare_native_stackinfo /*puts 2*4 additional bytes on stack*/
1143 #if 0
1144                 sub             $16,%esp                                 /* build stack frame (4 * 4 bytes) */
1145
1146                 mov             20(%esp),%eax
1147                 mov             %eax,(%esp)
1148
1149                 call    builtin_asm_get_stackframeinfo
1150                 movl    $0,12(%esp)
1151                 mov     %eax,8(%esp)
1152                 mov     (%eax),%ebx
1153                 mov     %ebx,4(%esp)
1154                 mov     %esp,%ecx
1155                 add     $4,%ecx
1156                 mov     %ecx,(%eax)
1157 #endif
1158                 push    %eax
1159                 call    builtin_new
1160                 add     $4,%esp
1161
1162                 call    asm_remove_native_stackinfo /*first element on stack is return adress again*/
1163 #if 0           
1164                 call    
1165                 mov     4(%esp),%ebx
1166                 mov     8(%esp),%ecx
1167                 mov     %ebx,(%ecx)
1168
1169                 add             $16,%esp
1170 #endif
1171                 jmp L_builtin_new_patch
1172
1173
1174 L_builtin_new_noinit:
1175                 mov 4(%esp),%eax
1176                 push %eax
1177                 call builtin_new
1178                 add $4,%esp
1179                 /*jmp L_builtin_new_patch*/
1180
1181 L_builtin_new_patch:
1182 /*add patching code here */
1183                 lea builtin_new,%edx
1184                 mov (%esp),%ecx
1185                 mov %edx,-6(%ecx)       /*patch calling instruction, t directly call builtin_new the next time*/
1186                 ret
1187
1188
1189
1190
1191
1192
1193 asm_getclassvalues_atomic:
1194 _crit_restart2:
1195         mov     4(%esp),%ecx        /* super */
1196         mov     8(%esp),%edx        /* sub */
1197 _crit_begin2:
1198         mov     offbaseval(%ecx),%eax
1199         mov     offdiffval(%ecx),%ecx
1200         mov     offbaseval(%edx),%edx
1201 _crit_end2:
1202         push    %ebx
1203         mov     16(%esp),%ebx      /* out */
1204         mov     %eax,offcast_super_baseval(%ebx)
1205         mov     %ecx,offcast_super_diffval(%ebx)
1206         mov     %edx,offcast_sub_baseval(%ebx)
1207         pop     %ebx
1208         ret
1209
1210         .data
1211
1212 asm_criticalsections:
1213 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
1214         .long   _crit_begin1
1215         .long   _crit_end1
1216         .long   _crit_restart1
1217         .long   _crit_begin2
1218         .long   _crit_end2
1219         .long   _crit_restart2
1220 #endif
1221         .long 0
1222
1223
1224
1225 /************************ function asm_prepare_native_stackinfo ****************************
1226 *                                                                                          *
1227 *    creates a stackfame for the begin of a native function (either builtin or not )       *
1228 *    expected stack at begin of function                                                   *
1229 *                                        ....                                              *
1230 *                   address of the jit call which invokes the native                       *
1231 *                   begin address of stack frame of the java method                        *
1232 *                   method pointer or 0 (for built ins)                                    *
1233 *                   return address                                                         *
1234 *                                                                                          *
1235 *    at end of function:                                                                   *
1236 *                                          ...                                             *
1237 *                   address of the jit call which invokes the native                       *
1238 *                   begin address of stack frame of the java method                        *
1239 *                   method pointer or 0 (for built ins)                                    *
1240 *                   address of thread specific top of native list                          *
1241 *                   old value of thread specific head                                      *
1242 *                   return address                                                         *
1243 *                                                                                          *
1244 *                                        ....                                              *
1245 * This thing is less efficient than the original #define (callerside)                      *
1246 * destroyes REG_ITMP2, keeps REG_ITMP1                                                     *
1247 ********************************************************************************************/
1248
1249
1250 asm_prepare_native_stackinfo:
1251         sub $8,%esp
1252         mov 8(%esp),%ecx
1253         mov %ecx,(%esp)
1254         push %eax
1255         lea     builtin_asm_get_stackframeinfo,%ecx
1256         call    *%ecx
1257         mov %eax, 12(%esp)
1258         mov (%eax),%ecx
1259         mov %ecx,8(%esp)
1260         mov %esp,%ecx
1261         add $8,%ecx
1262         mov %ecx,(%eax)
1263         pop %eax
1264         ret
1265 #if 0
1266 #define PREPARE_NATIVE_STACKINFO \
1267     i386_push_reg(cd, REG_ITMP1);       /*save itmp1, needed by some stubs */ \
1268     i386_alu_imm_reg(cd, I386_SUB, 2*4, REG_SP); /* build stack frame (2 * 4 bytes), together with previous =3*4 */ \
1269     i386_mov_imm_reg(cd, (s4) codegen_stubcalled,REG_ITMP1); \
1270     i386_call_reg(cd, REG_ITMP1);                /*call    codegen_stubcalled*/ \
1271     i386_mov_imm_reg(cd, (s4) builtin_asm_get_stackframeinfo,REG_ITMP1); \
1272     i386_call_reg(cd, REG_ITMP1);                /*call    builtin_asm_get_stackframeinfo*/ \
1273     i386_mov_reg_membase(cd, REG_RESULT,REG_SP,1*4); /* save thread pointer  to native call stack*/ \
1274     i386_mov_membase_reg(cd, REG_RESULT,0,REG_ITMP2); /* get old value of thread specific native call stack */ \
1275     i386_mov_reg_membase(cd, REG_ITMP2,REG_SP,0*4);     /* store value on stack */ \
1276     i386_mov_reg_membase(cd, REG_SP,REG_RESULT,0); /* store pointer to new stack frame information */ \
1277     i386_mov_membase_reg(cd, REG_SP,2*4,REG_ITMP1); /* restore ITMP1, need for some stubs*/ \
1278     i386_mov_imm_membase(cd, 0,REG_SP, 2*4);    /* builtin */
1279 #endif
1280
1281
1282 /************************ function asm_remove _native_stackinfo *******************************************
1283 *                                                                                                         *
1284 *    creates a stackfame for the begin of a native function (either builtin or not)                       *
1285 *    expected stack at begin of function                                                                  *
1286 *                   address of the jit call which invokes the native                                      *
1287 *                   begin address of stack frame of the java method                                       *
1288 *                   method pointer or 0 (for built ins)                                                   *
1289 *                   address thread specific top of native list                                            *
1290 *                   old value of thread specific head                                                     *
1291 *                   return address                                                                        *
1292 *                                                                                                         *
1293 *    at end of function:                                                                                  *
1294 *                             ....                                                                        *
1295 *                   return adresss of the jit call which invokes the native                               *
1296 *                   return address                                                                        *
1297 *                                                                                                         *
1298 *                   REG_ITMP2_XPC = address of the jit call which invokes the native                      *
1299 *                                                                                                         *
1300 *                                                                                                         *
1301 * This thing is less efficient than the original #define (callerside), uses ITMP3,uses ITMP3,keeps ITMP1  *
1302 ***********************************************************************************************************/
1303
1304 asm_remove_native_stackinfo:
1305         mov 4(%esp),%ecx
1306         mov 8(%esp),%edx
1307         mov %ecx,(%edx)
1308         pop %edx
1309         add $16,%esp
1310         push %edx
1311         ret
1312
1313 #if 0
1314 #define REMOVE_NATIVE_STACKINFO \
1315     i386_mov_membase_reg(cd, REG_SP,0,REG_ITMP2); \
1316     i386_mov_membase_reg(cd, REG_SP,4,REG_ITMP3); \
1317     i386_mov_reg_membase(cd, REG_ITMP2,REG_ITMP3,0); \
1318     i386_alu_imm_reg(cd, I386_ADD,3*4,REG_SP);
1319 #endif
1320
1321
1322
1323
1324 /*
1325  * These are local overrides for various environment variables in Emacs.
1326  * Please do not remove this and leave it at the end of the file, where
1327  * Emacs will automagically detect them.
1328  * ---------------------------------------------------------------------
1329  * Local variables:
1330  * mode: asm
1331  * indent-tabs-mode: t
1332  * c-basic-offset: 4
1333  * tab-width: 4
1334  * End:
1335  */