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