* Merged in twisti-branch.
[cacao.git] / src / vm / jit / mips / asmpart.S
1 /* src/vm/jit/mips/asmpart.S - Java-C interface functions for MIPS
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
29    Changes: Christian Thalinger
30             Edwin Steiner
31
32    $Id: asmpart.S 7455 2007-03-05 15:46:53Z tbfg $
33
34 */
35
36
37 #include "config.h"
38
39 #include "vm/jit/mips/md-abi.h"
40 #include "vm/jit/mips/md-asm.h"
41 #include "vm/jit/mips/offsets.h"
42
43 #include "vm/jit/abi-asm.h"
44 #include "vm/jit/methodheader.h"
45
46
47         .text
48         .set    noat
49
50
51 /* export functions ***********************************************************/
52
53         .globl asm_vm_call_method
54         .globl asm_vm_call_method_int
55         .globl asm_vm_call_method_long
56         .globl asm_vm_call_method_float
57         .globl asm_vm_call_method_double
58         .globl asm_vm_call_method_exception_handler
59         .globl asm_vm_call_method_end
60
61         .globl asm_call_jit_compiler
62
63         .globl asm_handle_exception
64         .globl asm_handle_nat_exception
65
66         .globl asm_abstractmethoderror
67
68         .globl asm_patcher_wrapper
69
70 #if defined(ENABLE_REPLACEMENT)
71         .globl asm_replacement_out
72         .globl asm_replacement_in
73 #endif
74
75         .globl asm_getclassvalues_atomic
76         .globl asm_criticalsections
77
78         .globl compare_and_swap
79
80
81 /* asm_vm_call_method **********************************************************
82 *                                                                              *
83 *   This function calls a Java-method (which possibly needs compilation)       *
84 *   with up to 4 address parameters.                                           *
85 *                                                                              *
86 *   This functions calls the JIT-compiler which eventually translates the      *
87 *   method into machine code.                                                  *
88 *                                                                              *
89 *   A possibly throwed exception will be returned to the caller as function    *
90 *   return value, so the java method cannot return a fucntion value (this      *
91 *   function usually calls 'main' and '<clinit>' which do not return a         *
92 *   function value).                                                           *
93 *                                                                              *
94 *   C-prototype:                                                               *
95 *    javaobject_header *asm_calljavafunction (methodinfo *m,                   *
96 *         void *arg1, void *arg2, void *arg3, void *arg4);                     *
97 *                                                                              *
98 *******************************************************************************/
99
100         .ent    asm_vm_call_method
101
102         .align  3
103
104 #if SIZEOF_VOID_P == 8
105
106         .dword  0                           /* catch type all                     */
107         .dword  0                           /* handler pc                         */
108         .dword  0                           /* end pc                             */
109         .dword  0                           /* start pc                           */
110         .word   1                           /* extable size                       */
111         .word   0                           /* 4-byte ALIGNMENT PADDING           */
112         .dword  0                           /* line number table start            */
113         .dword  0                           /* line number table size             */
114         .word   0                           /* 4-byte ALIGNMENT PADDING           */
115         .word   0                           /* fltsave                            */
116         .word   0                           /* intsave                            */
117         .word   0                           /* isleaf                             */
118         .word   0                           /* IsSync                             */
119         .word   0                           /* frame size                         */
120         .dword  0                           /* codeinfo pointer                   */
121
122 #else /* SIZEOF_VOID_P == 8 */
123
124         .word   0                           /* catch type all                     */
125         .word   0                           /* handler pc                         */
126         .word   0                           /* end pc                             */
127         .word   0                           /* start pc                           */
128         .word   1                           /* extable size                       */
129         .word   0                           /* line number table start            */
130         .word   0                           /* line number table size             */
131         .word   0                           /* fltsave                            */
132         .word   0                           /* intsave                            */
133         .word   0                           /* isleaf                             */
134         .word   0                           /* IsSync                             */
135         .word   0                           /* frame size                         */
136         .word   0                           /* method pointer (pointer to name)   */
137
138 #endif /* SIZEOF_VOID_P == 8 */
139
140 asm_vm_call_method:
141 asm_vm_call_method_int:
142 asm_vm_call_method_long:
143 asm_vm_call_method_float:
144 asm_vm_call_method_double:
145         .set    noreorder                 /* XXX we need to recompute pv          */
146
147         aaddiu  sp,sp,-12*8               /* allocate stack space (only 11 needed)*/
148         ast     ra,0*8(sp)                /* save return address                  */
149
150         bal     L_asm_vm_call_method_compute_pv
151         ast     pv,1*8(sp)                /* procedure vector                     */
152 L_asm_vm_call_method_compute_pv:
153         aaddiu  pv,ra,-4*4
154
155         ast     s7,3*8(sp)
156
157 #if SIZEOF_VOID_P == 8
158         sdc1    fss0,5*8(sp)              /* save non JavaABI saved flt registers */
159         sdc1    fss1,6*8(sp)
160         sdc1    fss2,7*8(sp)
161         sdc1    fss3,8*8(sp)
162         sdc1    fss4,9*8(sp)
163         sdc1    fss5,10*8(sp)
164 #endif
165
166         ast     a0,4*8(sp)                /* save method pointer for compiler     */
167
168         move    t0,a2                     /* address of first block               */
169         move    s7,a1                     /* argument count                       */
170         blez    s7,calljava_argsloaded
171         nop
172
173 #if SIZEOF_VOID_P == 8
174
175         ald     a0,offvmargdata(t0)
176         ldc1    fa0,offvmargdata(t0)
177         aaddi   s7,s7,-1
178         blez    s7,calljava_argsloaded
179         nop
180
181         ald     a1,offvmargdata+sizevmarg*1(t0)
182         ldc1    fa1,offvmargdata+sizevmarg*1(t0)
183         aaddi   s7,s7,-1
184         blez    s7,calljava_argsloaded
185         nop
186
187         ald     a2,offvmargdata+sizevmarg*2(t0)
188         ldc1    fa2,offvmargdata+sizevmarg*2(t0)
189         aaddi   s7,s7,-1
190         blez    s7,calljava_argsloaded
191         nop
192
193         ald     a3,offvmargdata+sizevmarg*3(t0)
194         ldc1    fa3,offvmargdata+sizevmarg*3(t0)
195         aaddi   s7,s7,-1
196         blez    s7,calljava_argsloaded
197         nop
198
199         ald     a4,offvmargdata+sizevmarg*4(t0)
200         ldc1    fa4,offvmargdata+sizevmarg*4(t0)
201         aaddi   s7,s7,-1
202         blez    s7,calljava_argsloaded
203         nop
204
205         ald     a5,offvmargdata+sizevmarg*5(t0)
206         ldc1    fa5,offvmargdata+sizevmarg*5(t0)
207         aaddi   s7,s7,-1
208         blez    s7,calljava_argsloaded
209         nop
210
211         ald     a6,offvmargdata+sizevmarg*6(t0)
212         ldc1    fa6,offvmargdata+sizevmarg*6(t0)
213         aaddi   s7,s7,-1
214         blez    s7,calljava_argsloaded
215         nop
216
217         ald     a7,offvmargdata+sizevmarg*7(t0)
218         ldc1    fa7,offvmargdata+sizevmarg*7(t0)
219         aaddi   s7,s7,-1
220
221 #else /* SIZEOF_VOID_P == 8 */
222
223 #if WORDS_BIGENDIAN == 1
224         ald     a0,offvmargdata+4(t0)
225 #else
226         ald     a0,offvmargdata(t0)
227 #endif
228 #if !defined(ENABLE_SOFT_FLOAT)
229         ldc1    fa0,offvmargdata(t0)
230 #endif
231         aaddi   s7,s7,-1
232         blez    s7,calljava_argsloaded
233
234 #if WORDS_BIGENDIAN == 1
235         ald     a1,offvmargdata+4+sizevmarg*1(t0)
236 #else
237         ald     a1,offvmargdata+sizevmarg*1(t0)
238 #endif
239 #if !defined(ENABLE_SOFT_FLOAT)
240         ldc1    fa1,offvmargdata+sizevmarg*1(t0)
241 #endif
242         aaddi   s7,s7,-1
243         blez    s7,calljava_argsloaded
244
245 #if WORDS_BIGENDIAN == 1
246         ald     a2,offvmargdata+4+sizevmarg*2(t0)
247 #else
248         ald     a2,offvmargdata+sizevmarg*2(t0)
249 #endif
250         aaddi   s7,s7,-1
251         blez    s7,calljava_argsloaded
252
253 #if WORDS_BIGENDIAN == 1
254         ald     a3,offvmargdata+4+sizevmarg*3(t0)
255 #else
256         ald     a3,offvmargdata+sizevmarg*3(t0)
257 #endif
258         aaddi   s7,s7,-1
259         blez    s7,calljava_argsloaded
260
261 #endif /* SIZEOF_VOID_P == 8 */
262
263 calljava_argsloaded:
264         move    t4,sp                     /* save stack pointer                   */
265         blez    s7,calljava_nocopy
266         nop
267
268 #if SIZEOF_VOID_P == 4
269         aaddiu  s7,s7,4                   /* add stack space for 4 arguments      */
270 #endif
271         subu    t1,zero,s7                /* remaining argument count (negative)  */
272         sll     t2,t1,3                   /* calculate stackframe size            */
273         aaddu   sp,sp,t2                  /* create stackframe                    */
274         aaddu   t2,t2,t4                  /* also set temp sp                     */
275 #if SIZEOF_VOID_P == 4
276         aaddiu  t2,t2,4*8                 /* skip stack space for 4 arguments     */
277         addiu   t1,t1,4
278 #endif
279
280 calljava_copyloop:
281 #if SIZEOF_VOID_P == 8
282         ald     t3,offvmargdata+sizevmarg*8(t0)
283 #else
284 # if WORDS_BIGENDIAN == 1
285         ald     t3,offvmargdata+4+sizevmarg*4(t0)
286 # else
287         ald     t3,offvmargdata+sizevmarg*4(t0)
288 # endif
289 #endif
290         ast     t3,0(t2)                  /* store argument on stack              */
291         addi    t1,t1,1                   /* count 1 argument                     */
292         aaddi   t0,t0,sizevmarg           /* load address of next block           */
293         aaddi   t2,t2,8                   /* increase stack position              */
294         bnez    t1,calljava_copyloop      /* all arguments copied?                */
295         nop
296
297 calljava_nocopy:
298         ald     itmp1,4*8(t4)             /* pass method pointer via itmp1        */
299
300         ala     mptr,asm_call_jit_compiler/* fake virtual function call (2 instr) */
301         ast     mptr,2*8(t4)              /* store function address               */
302         ala     mptr,1*8(t4)              /* set method pointer                   */
303
304         ald     pv,1*8(mptr)              /* method call as in Java               */
305         jalr    pv                        /* call JIT compiler                    */
306         nop
307 L_asm_vm_call_method_recompute_pv:
308 #if SIZEOF_VOID_P == 8
309         aaddiu  pv,ra,-76*4               /* recompute procedure vector           */
310 #else
311         aaddiu  pv,ra,(asm_vm_call_method - L_asm_vm_call_method_recompute_pv)
312 #endif
313
314         .set    reorder                   /* XXX we need to recompute pv          */
315
316         sll     t1,s7,3                   /* remove argument stackframe           */
317         aaddu   sp,sp,t1
318
319 calljava_return2:
320         ald     ra,0*8(sp)                /* restore return address               */
321         ald     pv,1*8(sp)                /* restore procedure vector             */
322         ald     s7,3*8(sp)
323
324 #if SIZEOF_VOID_P == 8
325         ldc1    fss0,5*8(sp)              /* restore non JavaABI saved flt regs   */
326         ldc1    fss1,6*8(sp)
327         ldc1    fss2,7*8(sp)
328         ldc1    fss3,8*8(sp)
329         ldc1    fss4,9*8(sp)
330         ldc1    fss5,10*8(sp)
331 #endif
332
333         aaddiu  sp,sp,12*8                /* free stack space                     */
334         j       ra                        /* return                               */
335
336 asm_vm_call_method_exception_handler:
337         sll     t1,s7,3                   /* remove stackframe                    */
338         aaddu   sp,sp,t1
339 #if SIZEOF_VOID_P == 4
340         aaddiu  sp,sp,-4*4                /* reserve space for 1 argument         */
341 #endif
342
343         move    a0,itmp1                  
344         jal     builtin_throw_exception
345 #if SIZEOF_VOID_P == 4
346         aaddiu  sp,sp,4*4
347 #endif
348 asm_vm_call_method_end:
349         b       calljava_return2
350
351         .end    asm_vm_call_method
352
353
354 /****************** function asm_call_jit_compiler *****************************
355 *                                                                              *
356 *   invokes the compiler for untranslated JavaVM methods.                      *
357 *                                                                              *
358 *   Register REG_ITEMP1 contains a pointer to the method info structure        *
359 *   (prepared by createcompilerstub). Using the return address in R31 and the  *
360 *   offset in the LDA instruction or using the value in methodptr R25 the      *
361 *   patching address for storing the method address can be computed:           *
362 *                                                                              *
363 *   method address was either loaded using                                     *
364 *   M_ALD (REG_PV, REG_PV, a)        ; invokestatic/special    ($28)           *
365 *   M_JSR (REG_RA, REG_PV);                                                    *
366 *   M_NOP                                                                      *
367 *   M_LDA (REG_PV, REG_RA, val)                                                *
368 *   or                                                                         *
369 *   M_ALD (REG_PV, REG_METHODPTR, m) ; invokevirtual/interface ($25)           *
370 *   M_JSR (REG_RA, REG_PV);                                                    *
371 *   M_NOP                                                                      *
372 *   in the static case the method pointer can be computed using the            *
373 *   return address and the lda function following the jmp instruction          *
374 *                                                                              *
375 *******************************************************************************/
376
377         .ent    asm_call_jit_compiler
378
379 asm_call_jit_compiler:
380 #if SIZEOF_VOID_P == 8
381
382         aaddiu  sp,sp,-(ARG_CNT+2)*8  /* +2: keep stack 16-bytes aligned          */
383
384         ast     ra,0*8(sp)            /* save return address                      */
385
386         SAVE_ARGUMENT_REGISTERS(1)
387
388         move    a0,itmp1              /* pass methodinfo pointer                  */
389         move    a1,mptr               /* pass method pointer                      */
390         aaddiu  a2,sp,(ARG_CNT+2)*8   /* pass java sp                             */
391         move    a3,ra
392         jal     jit_asm_compile       /* call jit compiler                        */
393         move    pv,v0
394
395         ald     ra,0*8(sp)            /* restore return address                   */
396
397         RESTORE_ARGUMENT_REGISTERS(1)
398
399         aaddiu  sp,sp,(ARG_CNT+2)*8   /* remove stack frame                       */
400
401 #else /* SIZEOF_VOID_P == 8 */
402
403         aaddiu  sp,sp,-(ARG_CNT+2)*8  /* +4: keep stack 16-bytes aligned          */
404
405         ast     ra,4*4+0*4(sp)        /* save return address                      */
406
407         SAVE_ARGUMENT_REGISTERS(6)
408
409         move    a0,itmp1              /* pass methodinfo pointer                  */
410         move    a1,mptr               /* pass method pointer                      */
411         aaddiu  a2,sp,(ARG_CNT+2)*8   /* pass java sp                             */
412         move    a3,ra
413         jal     jit_asm_compile       /* call jit compiler                        */
414         move    pv,v0
415
416         ald     ra,4*4+0*4(sp)        /* restore return address                   */
417
418         RESTORE_ARGUMENT_REGISTERS(6)
419
420         aaddiu  sp,sp,(ARG_CNT+2)*8   /* remove stack frame                       */
421
422 #endif /* SIZEOF_VOID_P == 8 */
423
424         beqz    pv,L_asm_call_jit_compiler_exception
425
426         jr      pv                    /* and call method. The method returns      */
427                                       /* directly to the caller (ra).             */
428
429 L_asm_call_jit_compiler_exception:
430         aaddiu  sp,sp,-2*8
431         ast     ra,0*8(sp)
432         jal     exceptions_get_and_clear_exception
433         ald     ra,0*8(sp)
434         aaddiu  sp,sp,2*8
435
436         move    xptr,v0               /* get exception                            */
437         aaddiu  xpc,ra,-4             /* exception address is RA - 4              */
438         b       asm_handle_nat_exception
439
440         .end    asm_call_jit_compiler
441
442
443 /* asm_handle_exception ********************************************************
444
445    This function handles an exception. It does not use the usual calling
446    conventions. The exception pointer is passed in REG_ITMP1 and the
447    pc from the exception raising position is passed in REG_ITMP2. It searches
448    the local exception table for a handler. If no one is found, it unwinds
449    stacks and continues searching the callers.
450
451 *******************************************************************************/
452
453         .ent    asm_handle_nat_exception
454
455 asm_handle_nat_exception:
456 L_asm_handle_exception_stack_loop:
457 #if SIZEOF_VOID_P == 8
458         aaddiu  sp,sp,-6*8                  /* keep stack 16-byte aligned         */
459         ast     xptr,0*8(sp)                /* save exception pointer             */
460         ast     xpc,1*8(sp)                 /* save exception pc                  */
461         ast     ra,3*8(sp)                  /* save RA                            */
462         ast     zero,4*8(sp)                /* save maybe-leaf flag (cleared)     */
463 #else
464         aaddiu  sp,sp,-(4*4+6*8)            /* allocate stack                     */
465         ast     xptr,4*4+0*8(sp)            /* save exception pointer             */
466         ast     xpc,4*4+1*8(sp)             /* save exception pc                  */
467         ast     ra,4*4+3*8(sp)              /* save return address                */
468         ast     zero,4*4+4*8(sp)            /* save maybe-leaf flag (cleared)     */
469 #endif
470
471         move    a0,ra                       /* pass RA                            */
472         jal     md_codegen_get_pv_from_pc   /* get PV from RA                     */
473
474 #if SIZEOF_VOID_P == 8
475         ast     v0,2*8(sp)                  /* save PV                            */
476
477         ald     a0,0*8(sp)                  /* pass xptr                          */
478         ald     a1,1*8(sp)                  /* pass xpc                           */
479         move    a2,v0                       /* pass PV                            */
480         aaddiu  a3,sp,6*8                   /* pass Java SP                       */
481 #else
482         ast     v0,4*4+2*8(sp)              /* save data segment pointer          */
483
484         ald     a0,4*4+0*8(sp)              /* pass exception pointer             */
485         ald     a1,4*4+1*8(sp)              /* pass exception pc                  */
486         move    a2,v0                       /* pass data segment pointer          */
487         aaddiu  a3,sp,(4*4+6*8)             /* pass Java stack pointer            */
488 #endif
489
490         b       L_asm_handle_exception_continue
491
492         .aent    asm_handle_exception
493
494 asm_handle_exception:
495         aaddiu  sp,sp,-(ARG_CNT+TMP_CNT)*8  /* create maybe-leaf stackframe       */
496
497         SAVE_ARGUMENT_REGISTERS(0)          /* we save arg and temp registers in  */
498         SAVE_TEMPORARY_REGISTERS(ARG_CNT)   /* case this is a leaf method         */
499
500 #if SIZEOF_VOID_P == 8
501         aaddiu  sp,sp,-6*8                  /* allocate stack                     */
502         ast     xptr,0*8(sp)                /* save exception pointer             */
503         ast     pv,2*8(sp)                  /* save PV                            */
504         ast     ra,3*8(sp)                  /* save RA                            */
505         addu    t0,zero,1                   /* set maybe-leaf flag                */
506         ast     t0,4*8(sp)                  /* save maybe-leaf flag               */
507 #else
508         aaddiu  sp,sp,-(4*4+6*8)            /* allocate stack                     */
509         ast     xptr,4*4+0*8(sp)            /* save exception pointer             */
510         ast     xpc,4*4+1*8(sp)             /* save exception pc                  */
511         ast     pv,4*4+2*8(sp)              /* save data segment pointer          */
512         ast     ra,4*4+3*8(sp)              /* save return address                */
513         addu    t0,zero,1                   /* set maybe-leaf flag                */
514         ast     t0,4*4+4*8(sp)              /* save maybe-leaf flag               */
515 #endif
516
517         move    a0,xptr                     /* pass xptr                          */
518         move    a1,xpc                      /* pass xpc                           */
519         move    a2,pv                       /* pass PV                            */
520
521 #if SIZEOF_VOID_P == 8
522         aaddiu  a3,sp,(ARG_CNT+TMP_CNT+6)*8 /* pass Java SP                       */
523 #else
524         aaddiu  a3,sp,4*4+(ARG_CNT+TMP_CNT+6)*8 /* pass Java stack pointer        */
525 #endif
526
527 L_asm_handle_exception_continue:
528         jal     exceptions_handle_exception
529         
530         beqz    v0,L_asm_handle_exception_not_catched
531
532         move    xpc,v0                      /* move handlerpc into xpc            */
533
534 #if SIZEOF_VOID_P == 8
535         ald     xptr,0*8(sp)                /* restore exception pointer          */
536         ald     pv,2*8(sp)                  /* restore PV                         */
537         ald     ra,3*8(sp)                  /* restore RA                         */
538         ald     t0,4*8(sp)                  /* get maybe-leaf flag                */
539         aaddiu  sp,sp,6*8                   /* free stackframe                    */
540 #else
541         ald     xptr,4*4+0*8(sp)            /* restore exception pointer          */
542         ald     pv,4*4+2*8(sp)              /* restore data segment pointer       */
543         ald     ra,4*4+3*8(sp)              /* restore return address             */
544         ald     t0,4*4+4*8(sp)              /* get maybe-leaf flag                */
545         aaddiu  sp,sp,4*4+6*8               /* free stackframe                    */
546 #endif
547         
548         beqz    t0,L_asm_handle_exception_no_leaf
549
550         RESTORE_ARGUMENT_REGISTERS(0)       /* if this is a leaf method, we have  */
551         RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers  */
552         
553         aaddiu  sp,sp,(ARG_CNT+TMP_CNT)*8   /* remove maybe-leaf stackframe       */
554
555 L_asm_handle_exception_no_leaf:
556         jr      xpc                         /* jump to the handler                */
557
558 L_asm_handle_exception_not_catched:
559 #if SIZEOF_VOID_P == 8
560         ald     xptr,0*8(sp)                /* restore xptr                       */
561         ald     pv,2*8(sp)                  /* restore PV                         */
562         ald     ra,3*8(sp)                  /* restore RA                         */
563         ald     t0,4*8(sp)                  /* get maybe-leaf flag                */
564         aaddiu  sp,sp,6*8                   /* free stackframe                    */
565 #else
566         ald     xptr,4*4+0*8(sp)            /* restore xptr                       */
567         ald     pv,4*4+2*8(sp)              /* restore PV                         */
568         ald     ra,4*4+3*8(sp)              /* restore RA                         */
569         ald     t0,4*4+4*8(sp)              /* get maybe-leaf flag                */
570         aaddiu  sp,sp,4*4+6*8               /* free stackframe                    */
571 #endif
572         
573         beqz    t0,L_asm_handle_exception_no_leaf_stack
574
575         aaddiu  sp,sp,(ARG_CNT+TMP_CNT)*8   /* remove maybe-leaf stackframe       */
576         move    t0,zero                     /* clear the maybe-leaf flag          */
577
578 L_asm_handle_exception_no_leaf_stack:
579         lw      t1,FrameSize(pv)            /* get frame size                     */
580         aaddu   t1,sp,t1                    /* pointer to save area               */
581
582         lw      t2,IsLeaf(pv)               /* is leaf procedure                  */
583         bnez    t2,L_asm_handle_exception_no_ra_restore
584
585         ald     ra,-1*8(t1)                 /* restore ra                         */
586         aaddiu  t1,t1,-8                    /* t1--                               */
587
588 L_asm_handle_exception_no_ra_restore:
589         move    xpc,ra                      /* the new xpc is ra                  */
590         lw      t2,IntSave(pv)              /* t1 = saved int register count      */
591         ala     t3,ex_int2                  /* t3 = current pc                    */
592         sll     t2,t2,2                     /* t2 = register count * 4            */
593         asubu   t3,t3,t2                    /* t3 = IntSave - 4 * register count  */
594         jr      t3                          /* jump to save position              */
595
596         ald     s0,-8*8(t1)
597         ald     s1,-7*8(t1)
598         ald     s2,-6*8(t1)
599         ald     s3,-5*8(t1)
600         ald     s4,-4*8(t1)
601         ald     s5,-3*8(t1)
602         ald     s6,-2*8(t1)
603         ald     s7,-1*8(t1)
604
605 ex_int2:
606         sll     t2,t2,1               /* t2 = register count * 4 * 2              */
607         asubu   t1,t1,t2              /* t1 = t0 - 8 * register count             */
608
609         lw      t2,FltSave(pv)        /* t2 = saved flt register count            */
610         ala     t3,ex_flt2            /* t3 = current pc                          */
611         sll     t2,t2,2               /* t2 = register count * 4                  */
612         asubu   t3,t3,t2              /* t3 = ex_int_sav - 4 * register count     */
613         jr      t3                          /* jump to save position              */
614
615 #if SIZEOF_VOID_P == 8
616         ldc1    fs0,-4*8(t1)
617         ldc1    fs1,-3*8(t1)
618         ldc1    fs2,-2*8(t1)
619         ldc1    fs3,-1*8(t1)
620 #else /* SIZEOF_VOID_P == 8 */
621 # if !defined(ENABLE_SOFT_FLOAT)
622         ldc1    fs0,-4*8(t1)
623         ldc1    fs1,-3*8(t1)
624         ldc1    fs2,-2*8(t1)
625         ldc1    fs3,-1*8(t1)
626         ldc1    fs4,-1*8(t1)
627         ldc1    fs5,-1*8(t1)
628 # endif /* !defined(ENABLE_SOFT_FLOAT) */
629 #endif /* SIZEOF_VOID_P == 8 */
630
631 ex_flt2:
632         lw      t1,FrameSize(pv)            /* get frame size                     */
633         aaddu   sp,sp,t1                    /* unwind stack                       */
634         b       L_asm_handle_exception_stack_loop
635
636         .end    asm_handle_nat_exception
637
638
639 /* asm_abstractmethoderror *****************************************************
640
641    Creates and throws an AbstractMethodError.
642
643 *******************************************************************************/
644
645         .ent    asm_abstractmethoderror
646
647 asm_abstractmethoderror:
648         aaddiu  sp,sp,-2*8                  /* create stackframe                  */
649         ast     ra,0*8(sp)                  /* save return address                */
650         aaddiu  a0,sp,2*8                   /* pass java sp                       */
651         move    a1,ra                       /* pass exception address             */
652         jal     exceptions_asm_new_abstractmethoderror
653         ald     ra,0*8(sp)                  /* restore return address             */
654         aaddiu  sp,sp,2*8                   /* remove stackframe                  */
655
656         move    xptr,v0                     /* get exception pointer              */
657         aaddiu  xpc,ra,-4                   /* exception address is ra - 4        */
658         b       asm_handle_nat_exception
659
660         .end    asm_abstractmethoderror
661
662
663 /* asm_patcher_wrapper *********************************************************
664
665    XXX
666
667    Stack layout:
668      56   return address into JIT code (patch position)
669      48   pointer to virtual java_objectheader
670      40   machine code (which is patched back later)
671      32   machine code (which is patched back later)
672      24   machine code (which is patched back later)
673      16   unresolved class/method/field reference
674       8   data segment displacement from load instructions
675       0   patcher function pointer to call
676
677 *******************************************************************************/
678                 
679     .ent    asm_patcher_wrapper
680
681 asm_patcher_wrapper:
682 #if SIZEOF_VOID_P == 8
683
684         aaddiu  sp,sp,-((2+16+22+4)*8)/* create stack frame                       */
685
686         SAVE_RETURN_REGISTERS(0)      /* save 1 int/1 float return registers      */
687         SAVE_ARGUMENT_REGISTERS(2)    /* save 8 int/8 float argument registers    */
688         SAVE_TEMPORARY_REGISTERS(18)  /* save 5 int/16 float temporary registers  */
689
690         ast     itmp1,(2+16+22+0)*8(sp) /* save itmp1                             */
691         ast     itmp2,(2+16+22+1)*8(sp) /* save itmp2                             */
692         ast     ra,(2+16+22+2)*8(sp)  /* save method return address (for leafs)   */
693         ast     pv,(2+16+22+3)*8(sp)  /* save pv of calling java function         */
694
695         aaddiu  a0,sp,(2+16+22+4)*8   /* pass SP of patcher stub                  */
696         move    a1,pv                 /* pass PV                                  */
697         move    a2,ra                 /* pass RA (correct for leafs)              */
698         jal     patcher_wrapper
699         move    itmp3,v0
700
701         RESTORE_RETURN_REGISTERS(0)   /* restore 1 int/1 float return registers   */
702         RESTORE_ARGUMENT_REGISTERS(2) /* restore 8 int/8 float argument registers */
703         RESTORE_TEMPORARY_REGISTERS(18) /* restore 5 int/16 float temporary reg.  */
704
705         ald     itmp1,(2+16+22+0)*8(sp) /* restore itmp1                          */
706         ald     itmp2,(2+16+22+1)*8(sp) /* restore itmp2                          */
707         ald     ra,(2+16+22+2)*8(sp)  /* restore method return address (for leafs)*/
708         ald     pv,(2+16+22+3)*8(sp)  /* restore pv of calling java function      */
709
710         bnez    itmp3,L_asm_patcher_wrapper_exception
711
712         ald     itmp3,(7+2+16+22+4)*8(sp) /* load RA                              */
713         aaddiu  sp,sp,(8+2+16+22+4)*8 /* remove stack frame                       */
714
715         jr      itmp3                 /* jump to new patched code                 */
716
717 L_asm_patcher_wrapper_exception:
718         move    xptr,itmp3            /* get exception                            */
719         ald     xpc,(7+2+16+22+4)*8(sp) /* xpc is RA                              */
720         aaddiu  sp,sp,(8+2+16+22+4)*8 /* remove stack frame                       */
721
722 #else /* SIZEOF_VOID_P == 8 */
723
724         aaddiu  sp,sp,-((6+4+8+16+7)*4) /* create stack frame                     */
725                                       /* +7 keeps the SP 16-bytes aligned         */
726
727         SAVE_RETURN_REGISTERS(6)      /* save 2 int / 1 float return registers    */
728         SAVE_ARGUMENT_REGISTERS(10)   /* save 4 int / 2 float argument registers  */
729         SAVE_TEMPORARY_REGISTERS(18)  /* save 8 int / 4 float temporary registers */
730
731         ast     itmp1,(6+4+8+16+0)*4(sp) /* save itmp1                            */
732         ast     itmp2,(6+4+8+16+1)*4(sp) /* save itmp2                            */
733         ast     ra,(6+4+8+16+2)*4(sp) /* save method return address (for leafs)   */
734         ast     pv,(6+4+8+16+3)*4(sp) /* save pv of calling java function         */
735
736         aaddiu  a0,sp,(6+4+8+16+7)*4  /* pass SP of patcher stub                  */
737         move    a1,pv                 /* pass PV                                  */
738         move    a2,ra                 /* pass RA (correct for leafs)              */
739         jal     patcher_wrapper
740         move    itmp3,v0
741
742         RESTORE_RETURN_REGISTERS(6)   /* restore 2 int / 2 float return registers */
743         RESTORE_ARGUMENT_REGISTERS(10) /* restore 4 int / 2 float argument regs   */
744         RESTORE_TEMPORARY_REGISTERS(18) /* restore 8 int / 4 float temporary regs */
745
746         ald     itmp1,(6+4+8+16+0)*4(sp) /* restore itmp1                         */
747         ald     itmp2,(6+4+8+16+1)*4(sp) /* restore itmp2                         */
748         ald     ra,(6+4+8+16+2)*4(sp) /* restore method return address (for leafs)*/
749         ald     pv,(6+4+8+16+3)*4(sp) /* restore pv of calling java function      */
750
751         bnez    itmp3,L_asm_wrapper_patcher_exception
752
753         ald     itmp3,7*8+(6+4+8+16+7)*4(sp) /* load RA                           */
754         aaddiu  sp,sp,8*8+(6+4+8+16+7)*4 /* remove stack frame                    */
755
756         jr      itmp3                 /* jump to new patched code                 */
757
758 L_asm_wrapper_patcher_exception:
759         move    xptr,itmp3            /* get exception                            */
760         ald     xpc,7*8+(6+4+8+16+7)*4(sp) /* xpc is RA                           */
761         aaddiu  sp,sp,8*8+(6+4+8+16+7)*4 /* remove stack frame                    */
762
763 #endif /* SIZEOF_VOID_P == 8 */
764
765         b       asm_handle_exception
766
767         .end    asm_patcher_wrapper
768
769 #if defined(ENABLE_REPLACEMENT)
770                 
771 /* asm_replacement_out *********************************************************
772
773    This code is jumped to from the replacement-out stubs that are executed
774    when a thread reaches an activated replacement point.
775
776    The purpose of asm_replacement_out is to read out the parts of the
777    execution state that cannot be accessed from C code, store this state,
778    and then call the C function replace_me.
779
780    Stack layout:
781      16                 start of stack inside method to replace
782       0   rplpoint *    info on the replacement point that was reached
783
784    NOTE: itmp3 has been clobbered by the replacement-out stub!
785
786 *******************************************************************************/
787
788 /* some room to accomodate changes of the stack frame size during replacement */
789         /* XXX we should find a cleaner solution here */
790 #define REPLACEMENT_ROOM  512
791
792 #define REPLACEMENT_STACK_OFFSET ((sizeexecutionstate + REPLACEMENT_ROOM + 0xf) & ~0xf)
793
794         .ent asm_replacement_out
795
796 asm_replacement_out:
797     /* create stack frame */
798         aaddiu  sp,sp,-REPLACEMENT_STACK_OFFSET
799
800         /* save registers in execution state */
801         ast     $0 ,( 0*8+offes_intregs)(sp)
802         ast     $1 ,( 1*8+offes_intregs)(sp)
803         ast     $2 ,( 2*8+offes_intregs)(sp)
804         ast     $3 ,( 3*8+offes_intregs)(sp)
805         ast     $4 ,( 4*8+offes_intregs)(sp)
806         ast     $5 ,( 5*8+offes_intregs)(sp)
807         ast     $6 ,( 6*8+offes_intregs)(sp)
808         ast     $7 ,( 7*8+offes_intregs)(sp)
809         ast     $8 ,( 8*8+offes_intregs)(sp)
810         ast     $9 ,( 9*8+offes_intregs)(sp)
811         ast     $10,(10*8+offes_intregs)(sp)
812         ast     $11,(11*8+offes_intregs)(sp)
813         ast     $12,(12*8+offes_intregs)(sp)
814         ast     $13,(13*8+offes_intregs)(sp)
815         ast     $14,(14*8+offes_intregs)(sp)
816         ast     $15,(15*8+offes_intregs)(sp)
817         ast     $16,(16*8+offes_intregs)(sp)
818         ast     $17,(17*8+offes_intregs)(sp)
819         ast     $18,(18*8+offes_intregs)(sp)
820         ast     $19,(19*8+offes_intregs)(sp)
821         ast     $20,(20*8+offes_intregs)(sp)
822         ast     $21,(21*8+offes_intregs)(sp)
823         ast     $22,(22*8+offes_intregs)(sp)
824         ast     $23,(23*8+offes_intregs)(sp)
825         ast     $24,(24*8+offes_intregs)(sp)
826         ast     $25,(25*8+offes_intregs)(sp)
827         ast     $26,(26*8+offes_intregs)(sp)
828         ast     $27,(27*8+offes_intregs)(sp)
829         ast     $28,(28*8+offes_intregs)(sp)
830         ast     $29,(29*8+offes_intregs)(sp)
831         ast     $30,(30*8+offes_intregs)(sp)
832         ast     $31,(31*8+offes_intregs)(sp)
833
834 #if SIZEOF_VOID_P == 8
835
836         sdc1    $f0 ,( 0*8+offes_fltregs)(sp)
837         sdc1    $f1 ,( 1*8+offes_fltregs)(sp)
838         sdc1    $f2 ,( 2*8+offes_fltregs)(sp)
839         sdc1    $f3 ,( 3*8+offes_fltregs)(sp)
840         sdc1    $f4 ,( 4*8+offes_fltregs)(sp)
841         sdc1    $f5 ,( 5*8+offes_fltregs)(sp)
842         sdc1    $f6 ,( 6*8+offes_fltregs)(sp)
843         sdc1    $f7 ,( 7*8+offes_fltregs)(sp)
844         sdc1    $f8 ,( 8*8+offes_fltregs)(sp)
845         sdc1    $f9 ,( 9*8+offes_fltregs)(sp)
846         sdc1    $f10,(10*8+offes_fltregs)(sp)
847         sdc1    $f11,(11*8+offes_fltregs)(sp)
848         sdc1    $f12,(12*8+offes_fltregs)(sp)
849         sdc1    $f13,(13*8+offes_fltregs)(sp)
850         sdc1    $f14,(14*8+offes_fltregs)(sp)
851         sdc1    $f15,(15*8+offes_fltregs)(sp)
852         sdc1    $f16,(16*8+offes_fltregs)(sp)
853         sdc1    $f17,(17*8+offes_fltregs)(sp)
854         sdc1    $f18,(18*8+offes_fltregs)(sp)
855         sdc1    $f19,(19*8+offes_fltregs)(sp)
856         sdc1    $f20,(20*8+offes_fltregs)(sp)
857         sdc1    $f21,(21*8+offes_fltregs)(sp)
858         sdc1    $f22,(22*8+offes_fltregs)(sp)
859         sdc1    $f23,(23*8+offes_fltregs)(sp)
860         sdc1    $f24,(24*8+offes_fltregs)(sp)
861         sdc1    $f25,(25*8+offes_fltregs)(sp)
862         sdc1    $f26,(26*8+offes_fltregs)(sp)
863         sdc1    $f27,(27*8+offes_fltregs)(sp)
864         sdc1    $f28,(28*8+offes_fltregs)(sp)
865         sdc1    $f29,(29*8+offes_fltregs)(sp)
866         sdc1    $f30,(30*8+offes_fltregs)(sp)
867         sdc1    $f31,(31*8+offes_fltregs)(sp)
868
869 #else /* SIZEOF_VOID_P == 8 */
870
871         sdc1    $f0 ,( 0*8+offes_fltregs)(sp)
872         sdc1    $f2 ,( 2*8+offes_fltregs)(sp)
873         sdc1    $f4 ,( 4*8+offes_fltregs)(sp)
874         sdc1    $f6 ,( 6*8+offes_fltregs)(sp)
875         sdc1    $f8 ,( 8*8+offes_fltregs)(sp)
876         sdc1    $f10,(10*8+offes_fltregs)(sp)
877         sdc1    $f12,(12*8+offes_fltregs)(sp)
878         sdc1    $f14,(14*8+offes_fltregs)(sp)
879         sdc1    $f16,(16*8+offes_fltregs)(sp)
880         sdc1    $f18,(18*8+offes_fltregs)(sp)
881         sdc1    $f20,(20*8+offes_fltregs)(sp)
882         sdc1    $f22,(22*8+offes_fltregs)(sp)
883         sdc1    $f24,(24*8+offes_fltregs)(sp)
884         sdc1    $f26,(26*8+offes_fltregs)(sp)
885         sdc1    $f28,(28*8+offes_fltregs)(sp)
886         sdc1    $f30,(30*8+offes_fltregs)(sp)
887
888 #endif /* SIZEOF_VOID_P == 8 */
889         
890         /* calculate sp of method */
891         aaddiu  itmp1,sp,(REPLACEMENT_STACK_OFFSET + 2*8)
892         ast     itmp1,(offes_sp)(sp)
893
894         /* store pv */
895         ast     pv,(offes_pv)(sp)
896
897         /* call replace_me */
898         ald     a0,-(2*8)(itmp1)            /* arg0: rplpoint *                   */
899     move    a1,sp                       /* arg1: execution state              */
900     jal     replace_me                  /* call C function replace_me         */
901         jal     abort                       /* NEVER REACHED                      */
902
903         .end asm_replacement_out
904
905 /* asm_replacement_in **********************************************************
906
907    This code writes the given execution state and jumps to the replacement
908    code.
909
910    This function never returns!
911
912    NOTE: itmp3 is not restored!
913
914    C prototype:
915       void asm_replacement_in(executionstate *es);
916
917 *******************************************************************************/
918
919         .ent asm_replacement_in
920         
921 asm_replacement_in:
922         /* a0 == executionstate *es */
923
924         /* set new sp and pv */
925         ald     sp,(offes_sp)(a0)
926         ald     pv,(offes_pv)(a0)
927         
928         /* copy registers from execution state */
929         /* $0 is zero                     */
930         ald     $1 ,( 1*8+offes_intregs)(a0)
931         ald     $2 ,( 2*8+offes_intregs)(a0)
932         ald     $3 ,( 2*8+offes_intregs)(a0)
933         /* a0 is loaded below             */
934         ald     $5 ,( 5*8+offes_intregs)(a0)
935         ald     $6 ,( 6*8+offes_intregs)(a0)
936         ald     $7 ,( 7*8+offes_intregs)(a0)
937         ald     $8 ,( 8*8+offes_intregs)(a0)
938         ald     $9 ,( 9*8+offes_intregs)(a0)
939         ald     $10,(10*8+offes_intregs)(a0)
940         ald     $11,(11*8+offes_intregs)(a0)
941         ald     $12,(12*8+offes_intregs)(a0)
942         ald     $13,(13*8+offes_intregs)(a0)
943         ald     $14,(14*8+offes_intregs)(a0)
944         ald     $15,(15*8+offes_intregs)(a0)
945         ald     $16,(16*8+offes_intregs)(a0)
946         ald     $17,(17*8+offes_intregs)(a0)
947         ald     $18,(18*8+offes_intregs)(a0)
948         ald     $19,(19*8+offes_intregs)(a0)
949         ald     $20,(20*8+offes_intregs)(a0)
950         ald     $21,(21*8+offes_intregs)(a0)
951         ald     $22,(22*8+offes_intregs)(a0)
952         ald     $23,(23*8+offes_intregs)(a0)
953         ald     $24,(24*8+offes_intregs)(a0)
954         ald     $25,(25*8+offes_intregs)(a0)
955         ald     $26,(26*8+offes_intregs)(a0)
956         ald     $27,(27*8+offes_intregs)(a0)
957         ald     $28,(28*8+offes_intregs)(a0)
958         /* $29 is sp                      */
959         /* $30 is pv                      */
960         ald     $31,(31*8+offes_intregs)(a0)
961         
962 #if SIZEOF_VOID_P == 8
963
964         ldc1    $f0 ,( 0*8+offes_fltregs)(a0)
965         ldc1    $f1 ,( 1*8+offes_fltregs)(a0)
966         ldc1    $f2 ,( 2*8+offes_fltregs)(a0)
967         ldc1    $f3 ,( 3*8+offes_fltregs)(a0)
968         ldc1    $f4 ,( 4*8+offes_fltregs)(a0)
969         ldc1    $f5 ,( 5*8+offes_fltregs)(a0)
970         ldc1    $f6 ,( 6*8+offes_fltregs)(a0)
971         ldc1    $f7 ,( 7*8+offes_fltregs)(a0)
972         ldc1    $f8 ,( 8*8+offes_fltregs)(a0)
973         ldc1    $f9 ,( 9*8+offes_fltregs)(a0)
974         ldc1    $f10,(10*8+offes_fltregs)(a0)
975         ldc1    $f11,(11*8+offes_fltregs)(a0)
976         ldc1    $f12,(12*8+offes_fltregs)(a0)
977         ldc1    $f13,(13*8+offes_fltregs)(a0)
978         ldc1    $f14,(14*8+offes_fltregs)(a0)
979         ldc1    $f15,(15*8+offes_fltregs)(a0)
980         ldc1    $f16,(16*8+offes_fltregs)(a0)
981         ldc1    $f17,(17*8+offes_fltregs)(a0)
982         ldc1    $f18,(18*8+offes_fltregs)(a0)
983         ldc1    $f19,(19*8+offes_fltregs)(a0)
984         ldc1    $f20,(20*8+offes_fltregs)(a0)
985         ldc1    $f21,(21*8+offes_fltregs)(a0)
986         ldc1    $f22,(22*8+offes_fltregs)(a0)
987         ldc1    $f23,(23*8+offes_fltregs)(a0)
988         ldc1    $f24,(24*8+offes_fltregs)(a0)
989         ldc1    $f25,(25*8+offes_fltregs)(a0)
990         ldc1    $f26,(26*8+offes_fltregs)(a0)
991         ldc1    $f27,(27*8+offes_fltregs)(a0)
992         ldc1    $f28,(28*8+offes_fltregs)(a0)
993         ldc1    $f29,(29*8+offes_fltregs)(a0)
994         ldc1    $f30,(30*8+offes_fltregs)(a0)
995         ldc1    $f31,(31*8+offes_fltregs)(a0)
996
997 #else /* SIZEOF_VOID_P == 8 */
998
999         ldc1    $f0 ,( 0*8+offes_fltregs)(a0)
1000         ldc1    $f2 ,( 2*8+offes_fltregs)(a0)
1001         ldc1    $f4 ,( 4*8+offes_fltregs)(a0)
1002         ldc1    $f6 ,( 6*8+offes_fltregs)(a0)
1003         ldc1    $f8 ,( 8*8+offes_fltregs)(a0)
1004         ldc1    $f10,(10*8+offes_fltregs)(a0)
1005         ldc1    $f12,(12*8+offes_fltregs)(a0)
1006         ldc1    $f14,(14*8+offes_fltregs)(a0)
1007         ldc1    $f16,(16*8+offes_fltregs)(a0)
1008         ldc1    $f18,(18*8+offes_fltregs)(a0)
1009         ldc1    $f20,(20*8+offes_fltregs)(a0)
1010         ldc1    $f22,(22*8+offes_fltregs)(a0)
1011         ldc1    $f24,(24*8+offes_fltregs)(a0)
1012         ldc1    $f26,(26*8+offes_fltregs)(a0)
1013         ldc1    $f28,(28*8+offes_fltregs)(a0)
1014         ldc1    $f30,(30*8+offes_fltregs)(a0)
1015
1016 #endif /* SIZEOF_VOID_P == 8 */
1017
1018         /* load new pc */
1019
1020         ald     itmp3,offes_pc(a0)
1021
1022         /* load a0 */
1023         
1024         ald     a0,(4*8+offes_intregs)(a0)
1025
1026         /* jump to new code */
1027
1028         jr      itmp3
1029
1030         .end asm_replacement_in
1031
1032 #endif /* defined(ENABLE_REPLACEMENT) */
1033
1034
1035         .ent    asm_getclassvalues_atomic
1036
1037 asm_getclassvalues_atomic:
1038 _crit_restart:
1039 _crit_begin:
1040         lw      t0,offbaseval(a0)
1041         lw      t1,offdiffval(a0)
1042         lw      t2,offbaseval(a1)
1043 _crit_end:
1044         sw      t0,offcast_super_baseval(a2)
1045         sw      t1,offcast_super_diffval(a2)
1046         sw      t2,offcast_sub_baseval(a2)
1047         j       ra
1048
1049         .end    asm_getclassvalues_atomic
1050
1051     .data
1052
1053 asm_criticalsections:
1054 #if defined(ENABLE_THREADS)
1055     .dword  _crit_begin
1056     .dword  _crit_end
1057     .dword  _crit_restart
1058 #endif
1059     .dword  0
1060
1061
1062         .text
1063
1064         .ent    compare_and_swap
1065
1066 compare_and_swap:
1067 1:
1068         all     v0,0(a0)
1069         bne     v0,a1,2f
1070         move    t0,a2
1071         asc     t0,0(a0)
1072         beqz    t0,1b
1073 2:
1074         sync
1075         j       ra
1076
1077         .end    compare_and_swap
1078
1079
1080 /* Disable exec-stacks, required for Gentoo ***********************************/
1081
1082 #if defined(__GCC__) && defined(__ELF__)
1083         .section .note.GNU-stack,"",@progbits
1084 #endif
1085
1086
1087 /*
1088  * These are local overrides for various environment variables in Emacs.
1089  * Please do not remove this and leave it at the end of the file, where
1090  * Emacs will automagically detect them.
1091  * ---------------------------------------------------------------------
1092  * Local variables:
1093  * mode: asm
1094  * indent-tabs-mode: t
1095  * c-basic-offset: 4
1096  * tab-width: 4
1097  * End:
1098  * vim:noexpandtab:sw=4:ts=4:
1099  */