3192fcb41b0cec4243dec713ab12e665f1f14efe
[cacao.git] / src / vm / jit / m68k / patcher.c
1 /* src/vm/jit/m68k/patcher.c - m68k patcher functions
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 */
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31
32 #include "vm/types.h"
33
34 #include "mm/memory.h"
35 #include "native/native.h"
36
37 #include "vm/builtin.h"
38 #include "vm/exceptions.h"
39 #include "vm/initialize.h"
40 #include "vm/resolve.h"
41
42 #include "vm/jit/asmpart.h"
43 #include "vm/jit/patcher-common.h"
44 #include "vm/jit/md.h"
45 #include "vm/jit/stacktrace.h"
46
47 #include "vmcore/class.h"
48 #include "vmcore/field.h"
49 #include "vmcore/options.h"
50 #include "vmcore/references.h"
51
52 #include "codegen.h"
53
54 /* patcher_wrapper *************************************************************
55
56    Wrapper for all patchers.  It also creates the stackframe info
57    structure.
58
59    If the return value of the patcher function is false, it gets the
60    exception object, clears the exception pointer and returns the
61    exception.
62
63 *******************************************************************************/
64
65 #if 0
66 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
67 {
68         stackframeinfo_t   sfi;
69         u1                *xpc;
70         java_objectheader *o;
71         functionptr        f;
72         bool               result;
73         java_objectheader *e;
74
75         /* define the patcher function */
76
77         bool (*patcher_function)(u1 *);
78
79         /* get stuff from the stack */
80
81         xpc = (u1 *)                *((ptrint *) (sp + 6 * 4));
82         /* REG_ITMP3                              sp + 5 * 4 */
83         o   = (java_objectheader *) *((ptrint *) (sp + 4 * 4));
84         /*mcode =                                   *((u4*)      (sp + 3 * 4));*/
85         /*xmcode =                                      *((u4*)      (sp + 2 * 4));*/
86         /* unresolved file                        sp + 1 * 4 */
87         f   = (functionptr)         *((ptrint *) (sp + 0 * 4));
88
89
90         /* calculate and set the new return address */
91         xpc = xpc - PATCHER_CALL_SIZE;
92         *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
93
94
95         /* cast the passed function to a patcher function */
96         patcher_function = (bool (*)(u1 *)) (ptrint) f;
97
98         /* enter a monitor on the patching position */
99         PATCHER_MONITORENTER;
100
101         /* create the stackframeinfo */
102
103         /* RA is passed as NULL, but the XPC is correct and can be used in
104            stacktrace_stackframeinfo_add for md_codegen_get_pv_from_pc. */
105
106         /*
107         fprintf(stderr, "EXT STACKFRAME: sfi=%x pv=%x, sp=%x, xpc=%x\n", &sfi, pv, sp+7*4, xpc);
108         */
109         stacktrace_stackframeinfo_add(&sfi, pv, sp + 7 * 4, xpc, xpc);
110
111         /* call the proper patcher function */
112         result = (patcher_function)(sp);
113
114
115         /* remove the stackframeinfo */
116         stacktrace_stackframeinfo_remove(&sfi);
117
118         /* check for return value and exit accordingly */
119         if (result == false) {
120                 e = exceptions_get_and_clear_exception();
121
122                 PATCHER_MONITOREXIT;
123
124                 return e;
125         }
126         PATCHER_MARK_PATCHED_MONITOREXIT;
127
128         return NULL;
129 }
130 #endif
131
132
133 #define PATCH_BACK_ORIGINAL_MCODE  *((u8*)(pr->mpc)) = pr->mcode
134
135 /* patcher_initialize_class ****************************************************
136
137         just patch back original code
138
139 *******************************************************************************/
140
141
142 void patcher_patch_code(patchref_t *pr) 
143 {
144 #if 0
145         u1* xpc    = (u1 *)      *((ptrint *) (sp + 6 * 4));
146         u4 mcode  = *((u4*)      (sp + 3 * 4));
147         u4 xmcode = *((u4*)      (sp + 2 * 4));
148
149         *((u4*)(xpc))   = mcode;
150         *((u4*)(xpc+4)) = xmcode;
151 #endif
152
153         PATCH_BACK_ORIGINAL_MCODE;
154         md_icacheflush((void*)pr->mpc, 8);
155
156 }
157
158
159 #if 0
160 /* patcher_initialize_class ****************************************************
161
162    Initalizes a given classinfo pointer.  This function does not patch
163    any data.
164
165 *******************************************************************************/
166
167 bool patcher_initialize_class(patchref_t *pr)
168 {
169         classinfo *c;
170         u4                 xpc, mcode, xmcode;
171
172         /* get stuff from the stack */
173         c = (classinfo *) *((ptrint *) (sp + 1 * 4));
174
175         /* check if the class is initialized */
176         if (!(c->state & CLASS_INITIALIZED))
177                 if (!initialize_class(c))
178                         return false;
179
180         /* patch back original code */
181         patcher_patch_back(sp);
182
183         return true;
184 }
185 #endif
186
187 /* patcher_invokevirtual *******************************************************
188
189    Machine code:
190 0x4029bc46:   61ff 0000 00ba    bsrl 0x4029bd02
191 0x4029bc4c:   246f 0000         moveal %sp@(0),%a2
192 0x4029bc50:   266a 0000         moveal %a2@(0),%a3
193 0x4029bc54:   246b 0000         moveal %a3@(0),%a2      <-- patch this (0) offset
194 0x4029bc58:   4e92              jsr %a2@
195
196 *******************************************************************************/
197
198 bool patcher_invokevirtual(patchref_t *pr)
199 {
200         u1                *ra;
201         unresolved_method *um;
202         methodinfo        *m;
203         s2                 disp;
204
205         /* get stuff from the stack */
206         ra = (u1 *)                pr->mpc;
207         um = (unresolved_method *) pr->ref;
208
209         /* get the fieldinfo */
210         if (!(m = resolve_method_eager(um)))
211                 return false;
212
213         /* patch back original code */
214         PATCH_BACK_ORIGINAL_MCODE;
215
216         /* if we show NOPs, we have to skip them */
217         if (opt_shownops) ra += PATCHER_CALL_SIZE;
218
219         assert( *((u2*)(ra+8)) == 0x286b);
220
221         /* patch vftbl index */
222         disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
223         *((s2 *) (ra + 10)) = disp;
224
225         /* synchronize instruction cache */
226         md_icacheflush(ra + 10, 2);
227
228         return true;
229 }
230
231 /* patcher_invokestatic_special ************************************************
232
233    Machine code:
234
235    INVOKESPECIAL
236 0x402902bc:   61ff 0000 0076    bsrl 0x40290334
237 0x402902c2:   247c 0000 0000    moveal #0,%a2           <-- this #0
238 0x402902c8:   4e92              jsr %a2@
239
240 ******************************************************************************/
241
242 bool patcher_invokestatic_special(patchref_t *pr)
243 {
244         unresolved_method *um;
245         s4                 disp;
246         methodinfo        *m;
247
248         /* get stuff from the stack */
249         disp =                       pr->mpc;
250         um   = (unresolved_method *) pr->ref;
251
252         /* get the fieldinfo */
253         if (!(m = resolve_method_eager(um)))
254                 return false;
255
256         /* patch back original code */
257         PATCH_BACK_ORIGINAL_MCODE;
258
259         /* patch stubroutine */
260         if (opt_shownops) disp += PATCHER_CALL_SIZE;
261
262         *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
263
264         /* synchronize inst cache */
265
266         md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
267
268         return true;
269 }
270
271
272 #if 0
273 /* patcher_resolve_class *******************************************************
274
275    Resolves a given unresolved_class pointer.  This function does not
276    patch any data.
277
278 *******************************************************************************/
279
280 #ifdef ENABLE_VERIFIER
281 bool patcher_resolve_class(patchref_t *pr)
282 {
283         unresolved_class *uc;
284         classinfo        *c;
285         s4                              disp;
286
287         /* get stuff from the stack */
288         uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
289         disp =                    *((s4 *)     (sp + 6 * 4));
290
291         /* resolve the class */
292         if (!resolve_class(uc, resolveEager, false, &c))
293                 return false;
294
295         /* patch back original code */
296         PATCH_BACK_ORIGINAL_MCODE;
297
298         return true;
299 }
300 #endif /* ENABLE_VERIFIER */
301 #endif
302
303 #if 0
304 /* patcher_resolve_classref_to_classinfo ***************************************
305   ACONST:
306         0x4028f2ca:   2479 0000 0000    moveal 0x00000000,%a2
307 *******************************************************************************/
308 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
309 {
310         constant_classref *cr;
311         s4                 disp;
312         u1                *pv;
313         classinfo         *c;
314
315         /* get stuff from the stack */
316         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
317         disp =                       *((s4 *)     (sp + 6 * 4));
318
319         /* get the classinfo */
320         if (!(c = resolve_classref_eager(cr)))
321                 return false;
322
323         /* patch back original code */
324         PATCH_BACK_ORIGINAL_MCODE;
325
326         /* patch the classinfo pointer */
327         if (opt_shownops) disp += PATCHER_CALL_SIZE;
328         *((ptrint *) (disp+2)) = (ptrint) c;
329
330         /* synchronize inst cache */
331         md_icacheflush(disp+2, SIZEOF_VOID_P);
332
333         return true;
334 }
335 #endif
336
337 /* patcher_get_putstatic *******************************************************
338
339    Machine code:
340
341 *******************************************************************************/
342
343 bool patcher_get_putstatic(patchref_t *pr)
344 {
345         unresolved_field *uf;
346         s4                disp;
347         fieldinfo        *fi;
348
349         /* get stuff from the stack */
350         uf    = (unresolved_field *)  pr->ref;
351         disp  =                       pr->mpc;
352
353         /* get the fieldinfo */
354         if (!(fi = resolve_field_eager(uf)))
355                 return false;
356
357         /* check if the field's class is initialized */
358         if (!(fi->class->state & CLASS_INITIALIZED))
359                 if (!initialize_class(fi->class))
360                         return false;
361
362         /* patch back original code */
363         PATCH_BACK_ORIGINAL_MCODE;
364
365         /* patch the field value's address */
366         if (opt_shownops) disp += PATCHER_CALL_SIZE;
367         assert(*((uint16_t*)(disp)) == 0x247c);
368         *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
369
370         /* synchronize inst cache */
371         md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
372
373         return true;
374 }
375
376 /* patcher_get_putfield ********************************************************
377
378    Machine code:
379
380    <patched call position>
381
382 *******************************************************************************/
383
384 bool patcher_get_putfield(patchref_t *pr)
385 {
386         u1               *ra;
387         unresolved_field *uf;
388         fieldinfo        *fi;
389
390         ra = (u1 *)               pr->mpc;
391         uf = (unresolved_field *) pr->ref;
392
393         /* get the fieldinfo */
394         if (!(fi = resolve_field_eager(uf)))
395                 return false;
396
397         /* patch back original code */
398         PATCH_BACK_ORIGINAL_MCODE;
399
400         /* if we show NOPs, we have to skip them */
401         if (opt_shownops) ra += PATCHER_CALL_SIZE;
402
403         /* patch the field's offset */
404         if (IS_LNG_TYPE(fi->type)) {
405                 /*
406                  *      0x40d05bb2:     0x25440000      movel %d4,%a2@(0)
407                  *      0x40d05bb6:     0x25430004      movel %d3,%a2@(4)
408                  *                                            ^^^^
409                  *                                            both 0000 and 0004 have to be patched
410                  */
411
412                 assert( (fi->offset & 0x0000ffff) == fi->offset );
413
414                 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
415                 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
416
417                 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
418                 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
419
420                 md_icacheflush(ra, 2 * 4);
421         } else  {
422                 /*      Multiple cases here, int, adr, flt and dbl. */
423                 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 )    {
424                         /* flt/dbl case 
425                          * 0x40d3ddc2:     0xf22944c0 0x0000xxxx        fsmoves %a1@(0),%fp1
426                          *                                  ^^^^
427                          *                                  patch here 
428                          */
429                         assert( (fi->offset & 0x0000ffff) == fi->offset );
430                         assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
431                         *((int16_t*)(ra+4)) = (int16_t)fi->offset;
432
433                         md_icacheflush(ra+4, 1 * 4);
434                 } else  {
435                         /*      int/adr case
436                          *      0x40adb3f6:     0x254d0000      movel %a5,%a2@(0)
437                          *                            ^^^^                     ^
438                          *                            to be patched
439                          */
440                         assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
441                         assert( (fi->offset & 0x0000ffff) == fi->offset );
442                         *((int16_t*)(ra+2)) = (int16_t)fi->offset;
443
444                         /* synchronize instruction cache */
445                         md_icacheflush(ra, 1 * 4);
446                 }
447         }
448
449         return true;
450 }
451 /* patcher_resolve_classref_to_flags *******************************************
452
453    CHECKCAST/INSTANCEOF:
454
455
456 CHECKCAST:
457 0x4029b056:   61ff 0000 013e    bsrl 0x4029b196
458 0x4029b05c:   263c 0000 0000    movel #0,%d3            <-- patch this #0
459 0x4029b062:   0283 0000 0200    andil #512,%d3
460
461 INSTANCEOF:
462 0x402a4aa8:   61ff 0000 05c4    bsrl 0x402a506e
463 0x402a4aae:   283c 0000 0000    movel #0,%d4            <-- same here
464 0x402a4ab4:   0284 0000 0200    andil #512,%d4
465
466
467 *******************************************************************************/
468
469 bool patcher_resolve_classref_to_flags(patchref_t *pr)
470 {
471         constant_classref *cr;
472         s4                 disp;
473         classinfo         *c;
474
475         /* get stuff from the stack */
476         cr   = (constant_classref *) pr->ref;
477         disp =                       pr->mpc;
478
479         /* get the fieldinfo */
480         if (!(c = resolve_classref_eager(cr)))
481                 return false;
482
483         /* patch back original code */
484         PATCH_BACK_ORIGINAL_MCODE;
485
486         /* patch class flags */
487         if (opt_shownops) disp += PATCHER_CALL_SIZE;
488         assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
489         *((s4 *) (disp + 2)) = (s4) c->flags;
490
491         /* synchronize insn cache */
492         md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
493
494         return true;
495 }
496
497 /* patcher_resolve_classref_to_vftbl *******************************************
498
499    CHECKCAST (class):
500 0x4029b094:   61ff 0000 00b4    bsrl 0x4029b14a
501 0x4029b09a:   287c 0000 0000    moveal #0,%a4           <-- patch this #0
502 0x4029b0a0:   2668 0000         moveal %a0@(0),%a3
503
504    INSTANCEOF (class):
505 0x402a9300:   61ff 0000 0574    bsrl 0x402a9876
506 0x402a9306:   267c 0000 0000    moveal #0,%a3
507 0x402a930c:   246a 0000         moveal %a2@(0),%a2
508
509
510 *******************************************************************************/
511
512 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
513 {
514         constant_classref *cr;
515         s4                 disp;
516         classinfo         *c;
517
518         /* get stuff from the stack */
519         cr   = (constant_classref *) pr->ref;
520         disp =                       pr->mpc;
521
522         /* get the fieldinfo */
523         if (!(c = resolve_classref_eager(cr)))
524                 return false;
525
526         /* patch back original code */
527         PATCH_BACK_ORIGINAL_MCODE;
528
529         /* patch super class' vftbl */
530         if (opt_shownops) disp += PATCHER_CALL_SIZE;
531         assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
532
533         *((s4 *) (disp+2)) = (s4) c->vftbl;
534
535         /* synchronize insin cache */
536         md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
537
538         return true;
539 }
540
541 /* patcher_instanceof_interface ************************************************
542
543    Machine code:
544
545 0x402a92da:   61ff 0000 05c0    bsrl 0x402a989c
546 0x402a92e0:   246a 0000         moveal %a2@(0),%a2
547 0x402a92e4:   282a 0010         movel %a2@(16),%d4
548 0x402a92e8:   d8bc 0000 0000    addl #0,%d4             <-- this const
549 0x402a92ee:   4a84              tstl %d4
550 0x402a92f0:   6e0a              bles 0x402a92fc
551 0x402a92f2:   246a 0000         moveal %a2@(0),%a2      <-- this offset
552
553 *******************************************************************************/
554
555 bool patcher_instanceof_interface(patchref_t *pr)
556 {
557         u1                *ra;
558         constant_classref *cr;
559         classinfo         *c;
560         s4                 disp;
561
562         /* get stuff from the stack */
563
564         ra = (u1 *)                pr->mpc;
565         cr = (constant_classref *) pr->ref;
566
567         /* get the fieldinfo */
568         if (!(c = resolve_classref_eager(cr)))
569                 return false;
570
571         /* patch back original code */
572         PATCH_BACK_ORIGINAL_MCODE;
573
574         /* if we show NOPs, we have to skip them */
575         if (opt_shownops) ra += PATCHER_CALL_SIZE;
576                 
577         /* patch super class index */
578         disp = -(c->index);
579         assert( *((u2*)(ra + 8)) == 0xd8bc );
580         *((s4 *) (ra + 10 )) = disp;
581
582         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
583
584         assert( (s2)disp  == disp);
585         assert ( *((s2*)(ra+18)) == 0x246a );
586
587         *((s2 *) (ra + 20)) = disp;
588
589         /* synchronize instruction cache */
590         md_icacheflush((void*)(ra + 10), 12);
591
592         return true;
593 }
594
595 /* patcher_checkcast_interface *************************************************
596
597 0x402a9400:   61ff 0000 03b6    bsrl 0x402a97b8
598 0x402a9406:   266a 0000         moveal %a2@(0),%a3
599 0x402a940a:   282b 0010         movel %a3@(16),%d4
600 0x402a940e:   d8bc 0000 0000    addl #0,%d4             <-- this 0
601 0x402a9414:   4a84              tstl %d4
602 0x402a9416:   6e02              bgts 0x402a941a
603               1234              tstb %d0
604 0x402a9418:   4afc              illegal
605 0x402a941a:   286b 0000         moveal %a3@(0),%a4      <-- and this 0 offset
606
607 *******************************************************************************/
608
609 bool patcher_checkcast_interface(patchref_t *pr)
610 {
611         u1                *ra;
612         constant_classref *cr;
613         classinfo         *c;
614         s4                 disp;
615
616         /* get stuff from the stack */
617         ra = (u1 *)                pr->mpc;
618         cr = (constant_classref *) pr->ref;
619
620         /* get the fieldinfo */
621         if (!(c = resolve_classref_eager(cr)))
622                 return false;
623
624         /* patch back original code */
625         PATCH_BACK_ORIGINAL_MCODE;
626
627         /* if we show NOPs, we have to skip them */
628         if (opt_shownops) ra += PATCHER_CALL_SIZE;
629
630         /* patch super class index */
631         disp = -(c->index);
632         assert ( *((u2 *)(ra + 8)) == 0xd8bc );
633         *((s4 *) (ra + 10)) = disp;
634
635         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
636         assert( *((u2 *)(ra + 22)) == 0x286b );
637         assert( (s2)disp == disp);
638         *((s2 *) (ra + 24)) = disp;
639         
640         /* synchronize instruction cache */
641         md_icacheflush((void*)(ra + 10), 16);
642
643         return true;
644 }
645
646 #if 0
647 /* patcher_resolve_native_function *********************************************
648
649    XXX
650
651 *******************************************************************************/
652
653 bool patcher_resolve_native_function(patchref_t *pr)
654 {
655         methodinfo  *m;
656         s4           disp;
657         functionptr  f;
658
659         /* get stuff from the stack */
660         m    = (methodinfo *) pr->ref;
661         disp =                pr->mpc;
662
663         /* resolve native function */
664         if (!(f = native_resolve_function(m)))
665                 return false;
666
667         /* patch back original code */
668         PATCH_BACK_ORIGINAL_MCODE;
669
670         /* patch native function pointer */
671         if (opt_shownops) disp += PATCHER_CALL_SIZE;
672         *((ptrint *) (disp + 2)) = (ptrint) f;
673
674         /* synchronize data cache */
675         md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
676
677         return true;
678 }
679 #endif
680
681 /* patcher_invokeinterface *****************************************************
682
683    Machine code:
684 0x40adb03e:     moveal %a2@(0),%a3              0x266a0000              <-- no patching
685 0x40adb042:     moveal %a3@(0),%a3              0x266b0000              <-- patch this 0000
686 0x40adb046:     moveal %a3@(0),%a4              0xxxxx0000              <-- patch this 0000
687 0x40adb04a:     jsr %a4@                                0xxxxx                  
688
689
690 *******************************************************************************/
691
692 bool patcher_invokeinterface(patchref_t *pr)
693 {
694         u1                *ra;
695         unresolved_method *um;
696         methodinfo        *m;
697         s4                 disp;
698
699         /* get stuff from the stack */
700         ra = (u1 *)                pr->mpc;
701         um = (unresolved_method *) pr->ref;
702
703
704         /* get the fieldinfo */
705         if (!(m = resolve_method_eager(um)))
706                 return false;
707
708         /* patch back original code */
709         PATCH_BACK_ORIGINAL_MCODE;
710
711         /* if we show NOPs, we have to skip them */
712         if (opt_shownops) ra += PATCHER_CALL_SIZE;
713         assert( *((uint32_t*)ra) == 0x246f0000 );
714
715         /* patch interfacetable index (first #0) */
716         disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
717         /* XXX this disp is negative, check! 
718          * assert( (disp & 0x0000ffff) == disp);*/
719         *((uint16_t *) (ra + 5 * 2)) = disp;
720
721         /* patch method offset (second #0) */
722         disp = sizeof(methodptr) * (m - m->class->methods);
723         assert( (disp & 0x0000ffff) == disp);
724         *((uint16_t *) (ra + 7 * 2)) = disp;
725
726         /* synchronize instruction cache */
727         md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
728
729         return true;
730 }
731 /*
732  * These are local overrides for various environment variables in Emacs.
733  * Please do not remove this and leave it at the end of the file, where
734  * Emacs will automagically detect them.
735  * ---------------------------------------------------------------------
736  * Local variables:
737  * mode: c
738  * indent-tabs-mode: t
739  * c-basic-offset: 4
740  * tab-width: 4
741  * End:
742  * vim:noexpandtab:sw=4:ts=4:
743  */