328c7b514133df27acfab1a2d2ead052d11f4ee5
[cacao.git] / src / vm / jit / replace.c
1 /* src/vm/jit/replace.c - on-stack replacement of methods
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 #include "vm/types.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33
34 #include "arch.h"
35
36 #if defined(ENABLE_GC_CACAO)
37 # include "mm/cacao-gc/gc.h"
38 #endif
39
40 #include "mm/memory.h"
41
42 #include "threads/threads-common.h"
43
44 #include "toolbox/logging.h"
45
46 #include "vm/stringlocal.h"
47
48 #include "vm/jit/abi.h"
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/disass.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/md.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/replace.h"
55 #include "vm/jit/show.h"
56 #include "vm/jit/stack.h"
57
58 #include "vmcore/options.h"
59 #include "vmcore/classcache.h"
60
61
62 #define REPLACE_PATCH_DYNAMIC_CALL
63 /*#define REPLACE_PATCH_ALL*/
64
65 #if defined(ENABLE_VMLOG)
66 #include <vmlog_cacao.h>
67 #endif
68
69 /*** architecture-dependent configuration *************************************/
70
71 /* first unset the macros (default) */
72 #undef REPLACE_RA_BETWEEN_FRAMES
73 #undef REPLACE_RA_TOP_OF_FRAME
74 #undef REPLACE_RA_LINKAGE_AREA
75 #undef REPLACE_LEAFMETHODS_RA_REGISTER
76 #undef REPLACE_REG_RA
77
78 /* i386, x86_64 and m68k */
79 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
80 #define REPLACE_RA_BETWEEN_FRAMES
81 /* alpha */
82 #elif defined(__ALPHA__)
83 #define REPLACE_RA_TOP_OF_FRAME
84 #define REPLACE_LEAFMETHODS_RA_REGISTER
85 #define REPLACE_REG_RA REG_RA
86 /* powerpc */
87 #elif defined(__POWERPC__)
88 #define REPLACE_RA_LINKAGE_AREA
89 #define REPLACE_LEAFMETHODS_RA_REGISTER
90 #define REPLACE_REG_RA REG_ITMP3 /* the execution state has the LR in itmp3 */
91 /* s390 */
92 #elif defined(__S390__)
93 #define REPLACE_RA_TOP_OF_FRAME
94 #define REPLACE_REG_RA REG_ITMP3
95 #endif
96
97
98 /*** configuration of native stack slot size **********************************/
99
100 /* XXX this should be in md-abi.h files, probably */
101
102 #if defined(HAS_4BYTE_STACKSLOT)
103 #define SIZE_OF_STACKSLOT      4
104 #define STACK_SLOTS_PER_FLOAT  2
105 typedef u4 stackslot_t;
106 #else
107 #define SIZE_OF_STACKSLOT      8
108 #define STACK_SLOTS_PER_FLOAT  1
109 typedef u8 stackslot_t;
110 #endif
111
112
113 /*** debugging ****************************************************************/
114
115 #if !defined(NDEBUG)
116 static void java_value_print(s4 type, replace_val_t value);
117 static void replace_stackframeinfo_println(stackframeinfo *sfi);
118 #endif
119
120 #if !defined(NDEBUG)
121 #define DOLOG(code)        do{ if (opt_TraceReplacement > 1) { code; } } while(0)
122 #define DOLOG_SHORT(code)  do{ if (opt_TraceReplacement > 0) { code; } } while(0)
123 #else
124 #define DOLOG(code)
125 #define DOLOG_SHORT(code)
126 #endif
127
128
129 /*** statistics ***************************************************************/
130
131 #define REPLACE_STATISTICS
132
133 #if defined(REPLACE_STATISTICS)
134
135 static int stat_replacements = 0;
136 static int stat_frames = 0;
137 static int stat_recompile = 0;
138 static int stat_staticpatch = 0;
139 static int stat_unroll_inline = 0;
140 static int stat_unroll_call = 0;
141 static int stat_dist_frames[20] = { 0 };
142 static int stat_dist_locals[20] = { 0 };
143 static int stat_dist_locals_adr[10] = { 0 };
144 static int stat_dist_locals_prim[10] = { 0 };
145 static int stat_dist_locals_ret[10] = { 0 };
146 static int stat_dist_locals_void[10] = { 0 };
147 static int stat_dist_stack[10] = { 0 };
148 static int stat_dist_stack_adr[10] = { 0 };
149 static int stat_dist_stack_prim[10] = { 0 };
150 static int stat_dist_stack_ret[10] = { 0 };
151 static int stat_methods = 0;
152 static int stat_rploints = 0;
153 static int stat_regallocs = 0;
154 static int stat_dist_method_rplpoints[20] = { 0 };
155
156 #define REPLACE_COUNT(cnt)  (cnt)++
157 #define REPLACE_COUNT_IF(cnt, cond)  do{ if(cond) (cnt)++; } while(0)
158 #define REPLACE_COUNT_INC(cnt, inc)  ((cnt) += (inc))
159
160 #define REPLACE_COUNT_DIST(array, val)                               \
161     do {                                                             \
162         int limit = (sizeof(array) / sizeof(int)) - 1;               \
163         if ((val) < (limit)) (array)[val]++;                         \
164         else (array)[limit]++;                                       \
165     } while (0)
166
167 static void replace_statistics_source_frame(sourceframe_t *frame);
168
169 #else
170
171 #define REPLACE_COUNT(cnt)
172 #define REPLACE_COUNT_IF(cnt, cond)
173 #define REPLACE_COUNT_INC(cnt, inc)
174 #define REPLACE_COUNT_DIST(array, val)
175
176 #endif /* defined(REPLACE_STATISTICS) */
177
178
179 /*** constants used internally ************************************************/
180
181 #define TOP_IS_NORMAL    0
182 #define TOP_IS_ON_STACK  1
183 #define TOP_IS_IN_ITMP1  2
184 #define TOP_IS_VOID      3
185
186
187 /******************************************************************************/
188 /* PART I: Creating / freeing replacement points                              */
189 /******************************************************************************/
190
191
192 /* replace_create_replacement_point ********************************************
193  
194    Create a replacement point.
195   
196    IN:
197        jd...............current jitdata
198            iinfo............inlining info for the current position
199            rp...............pre-allocated (uninitialized) rplpoint
200            type.............RPLPOINT_TYPE constant
201            iptr.............current instruction
202            *pra.............current rplalloc pointer
203            javalocals.......the javalocals at the current point
204            stackvars........the stack variables at the current point
205            stackdepth.......the stack depth at the current point
206            paramcount.......number of parameters at the start of stackvars
207   
208    OUT:
209        *rpa.............points to the next free rplalloc
210   
211 *******************************************************************************/
212
213 static void replace_create_replacement_point(jitdata *jd,
214                                                                                          insinfo_inline *iinfo,
215                                                                                          rplpoint *rp,
216                                                                                          s4 type,
217                                                                                          instruction *iptr,
218                                                                                          rplalloc **pra,
219                                                                                          s4 *javalocals,
220                                                                                          s4 *stackvars,
221                                                                                          s4 stackdepth,
222                                                                                          s4 paramcount)
223 {
224         rplalloc *ra;
225         s4        i;
226         varinfo  *v;
227         s4        index;
228
229         ra = *pra;
230
231         REPLACE_COUNT(stat_rploints);
232
233         rp->method = (iinfo) ? iinfo->method : jd->m;
234         rp->pc = NULL;        /* set by codegen */
235         rp->callsize = 0;     /* set by codegen */
236         rp->regalloc = ra;
237         rp->flags = 0;
238         rp->type = type;
239         rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
240
241         /* XXX unify these two fields */
242         rp->parent = (iinfo) ? iinfo->rp : NULL;
243
244         /* store local allocation info of javalocals */
245
246         if (javalocals) {
247                 for (i = 0; i < rp->method->maxlocals; ++i) {
248                         index = javalocals[i];
249                         if (index == UNUSED)
250                                 continue;
251
252                         ra->index = i;
253                         if (index >= 0) {
254                                 v = VAR(index);
255                                 ra->flags = v->flags & (INMEMORY);
256                                 ra->regoff = v->vv.regoff;
257                                 ra->type = v->type;
258                         }
259                         else {
260                                 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
261                                 ra->type = TYPE_RET;
262                                 ra->flags = 0;
263                         }
264                         ra++;
265                 }
266         }
267
268         /* store allocation info of java stack vars */
269
270         for (i = 0; i < stackdepth; ++i) {
271                 v = VAR(stackvars[i]);
272                 ra->flags = v->flags & (INMEMORY);
273                 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
274                 ra->type  = v->type;
275                 /* XXX how to handle locals on the stack containing returnAddresses? */
276                 if (v->type == TYPE_RET) {
277                         assert(stackvars[i] >= jd->localcount);
278                         ra->regoff = v->vv.retaddr->nr;
279                 }
280                 else
281                         ra->regoff = v->vv.regoff;
282                 ra++;
283         }
284
285         /* total number of allocations */
286
287         rp->regalloccount = ra - rp->regalloc;
288
289         *pra = ra;
290 }
291
292
293 /* replace_create_inline_start_replacement_point *******************************
294
295    Create an INLINE_START replacement point.
296
297    IN:
298        jd...............current jitdata
299            rp...............pre-allocated (uninitialized) rplpoint
300            iptr.............current instruction
301            *pra.............current rplalloc pointer
302            javalocals.......the javalocals at the current point
303
304    OUT:
305        *rpa.............points to the next free rplalloc
306
307    RETURN VALUE:
308        the insinfo_inline * for the following inlined body
309
310 *******************************************************************************/
311
312 static insinfo_inline * replace_create_inline_start_replacement_point(
313                                                                                          jitdata *jd,
314                                                                                          rplpoint *rp,
315                                                                                          instruction *iptr,
316                                                                                          rplalloc **pra,
317                                                                                          s4 *javalocals)
318 {
319         insinfo_inline *calleeinfo;
320         rplalloc       *ra;
321
322         calleeinfo = iptr->sx.s23.s3.inlineinfo;
323
324         calleeinfo->rp = rp;
325
326         replace_create_replacement_point(jd, calleeinfo->parent, rp,
327                         RPLPOINT_TYPE_INLINE, iptr, pra,
328                         javalocals,
329                         calleeinfo->stackvars, calleeinfo->stackvarscount,
330                         calleeinfo->paramcount);
331
332         if (calleeinfo->synclocal != UNUSED) {
333                 ra = (*pra)++;
334                 ra->index  = RPLALLOC_SYNC;
335                 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
336                 ra->flags  = jd->var[calleeinfo->synclocal].flags & INMEMORY;
337                 ra->type   = TYPE_ADR;
338
339                 rp->regalloccount++;
340         }
341
342         return calleeinfo;
343 }
344
345
346 /* replace_create_replacement_points *******************************************
347  
348    Create the replacement points for the given code.
349   
350    IN:
351        jd...............current jitdata, must not have any replacement points
352   
353    OUT:
354        code->rplpoints.......set to the list of replacement points
355            code->rplpointcount...number of replacement points
356            code->regalloc........list of allocation info
357            code->regalloccount...total length of allocation info list
358            code->globalcount.....number of global allocations at the
359                                  start of code->regalloc
360   
361    RETURN VALUE:
362        true.............everything ok 
363        false............an exception has been thrown
364    
365 *******************************************************************************/
366
367 #define CLEAR_javalocals(array, method)                              \
368     do {                                                             \
369         for (i=0; i<(method)->maxlocals; ++i)                        \
370             (array)[i] = UNUSED;                                     \
371     } while (0)
372
373 #define COPY_OR_CLEAR_javalocals(dest, array, method)                \
374     do {                                                             \
375         if ((array) != NULL)                                         \
376             MCOPY((dest), (array), s4, (method)->maxlocals);         \
377         else                                                         \
378             CLEAR_javalocals((dest), (method));                      \
379     } while (0)
380
381 #define COUNT_javalocals(array, method, counter)                     \
382     do {                                                             \
383         for (i=0; i<(method)->maxlocals; ++i)                        \
384             if ((array)[i] != UNUSED)                                \
385                                 (counter)++;                                         \
386     } while (0)
387
388 bool replace_create_replacement_points(jitdata *jd)
389 {
390         codeinfo        *code;
391         registerdata    *rd;
392         basicblock      *bptr;
393         int              count;
394         methodinfo      *m;
395         rplpoint        *rplpoints;
396         rplpoint        *rp;
397         int              alloccount;
398         rplalloc        *regalloc;
399         rplalloc        *ra;
400         int              i;
401         instruction     *iptr;
402         instruction     *iend;
403         s4              *javalocals;
404         s4              *jl;
405         methoddesc      *md;
406         insinfo_inline  *iinfo;
407         s4               startcount;
408         s4               firstcount;
409 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
410         bool             needentry;
411 #endif
412
413         REPLACE_COUNT(stat_methods);
414
415         /* get required compiler data */
416
417         code = jd->code;
418         rd   = jd->rd;
419
420         /* assert that we wont overwrite already allocated data */
421
422         assert(code);
423         assert(code->m);
424         assert(code->rplpoints == NULL);
425         assert(code->rplpointcount == 0);
426         assert(code->regalloc == NULL);
427         assert(code->regalloccount == 0);
428         assert(code->globalcount == 0);
429
430         m = code->m;
431
432         /* set codeinfo flags */
433
434         code_flag_leafmethod(code);
435
436         /* in instance methods, we may need a rplpoint at the method entry */
437
438 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
439         if (!(m->flags & ACC_STATIC)) {
440                 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
441                 needentry = true;
442         }
443         else {
444                 needentry = false;
445         }
446 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
447
448         /* iterate over the basic block list to find replacement points */
449
450         count = 0;
451         alloccount = 0;
452
453         javalocals = DMNEW(s4, jd->maxlocals);
454
455         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
456
457                 /* skip dead code */
458
459                 if (bptr->flags < BBFINISHED)
460                         continue;
461
462                 /* get info about this block */
463
464                 m = bptr->method;
465                 iinfo = bptr->inlineinfo;
466
467                 /* initialize javalocals at the start of this block */
468
469                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
470
471                 /* iterate over the instructions */
472
473                 iptr = bptr->iinstr;
474                 iend = iptr + bptr->icount;
475                 startcount = count;
476                 firstcount = count;
477
478                 for (; iptr != iend; ++iptr) {
479                         switch (iptr->opc) {
480 #if defined(ENABLE_GC_CACAO)
481                                 case ICMD_BUILTIN:
482                                         md = iptr->sx.s23.s3.bte->md;
483                                         count++;
484                                         COUNT_javalocals(javalocals, m, alloccount);
485                                         alloccount += iptr->s1.argcount;
486                                         if (iinfo)
487                                                 alloccount -= iinfo->throughcount;
488                                         break;
489 #endif
490
491                                 case ICMD_INVOKESTATIC:
492                                 case ICMD_INVOKESPECIAL:
493                                 case ICMD_INVOKEVIRTUAL:
494                                 case ICMD_INVOKEINTERFACE:
495                                         INSTRUCTION_GET_METHODDESC(iptr, md);
496                                         count++;
497                                         COUNT_javalocals(javalocals, m, alloccount);
498                                         alloccount += iptr->s1.argcount;
499                                         if (iinfo)
500                                                 alloccount -= iinfo->throughcount;
501                                         break;
502
503                                 case ICMD_ISTORE:
504                                 case ICMD_LSTORE:
505                                 case ICMD_FSTORE:
506                                 case ICMD_DSTORE:
507                                 case ICMD_ASTORE:
508                                         stack_javalocals_store(iptr, javalocals);
509                                         break;
510
511                                 case ICMD_IRETURN:
512                                 case ICMD_LRETURN:
513                                 case ICMD_FRETURN:
514                                 case ICMD_DRETURN:
515                                 case ICMD_ARETURN:
516                                         alloccount += 1;
517                                         /* FALLTHROUGH! */
518                                 case ICMD_RETURN:
519                                         count++;
520                                         break;
521
522                                 case ICMD_INLINE_START:
523                                         iinfo = iptr->sx.s23.s3.inlineinfo;
524
525                                         count++;
526                                         COUNT_javalocals(javalocals, m, alloccount);
527                                         alloccount += iinfo->stackvarscount;
528                                         if (iinfo->synclocal != UNUSED)
529                                                 alloccount++;
530
531                                         m = iinfo->method;
532                                         /* javalocals may be set at next block start, or now */
533                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
534                                         break;
535
536                                 case ICMD_INLINE_BODY:
537                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
538
539                                         jl = iinfo->javalocals_start;
540                                         if (jl == NULL) {
541                                                 /* get the javalocals from the following block start */
542                                                 assert(bptr->next);
543                                                 jl = bptr->next->javalocals;
544                                         }
545                                         count++;
546                                         COUNT_javalocals(jl, m, alloccount);
547                                         break;
548
549                                 case ICMD_INLINE_END:
550                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
551                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
552                                         iinfo = iptr->sx.s23.s3.inlineinfo;
553                                         m = iinfo->outer;
554                                         if (iinfo->javalocals_end)
555                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
556                                         iinfo = iinfo->parent;
557                                         break;
558                         }
559
560                         if (iptr == bptr->iinstr)
561                                 firstcount = count;
562                 } /* end instruction loop */
563
564                 /* create replacement points at targets of backward branches */
565                 /* We only need the replacement point there, if there is no  */
566                 /* replacement point inside the block.                       */
567
568                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
569 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
570                         int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
571 #else
572                         int test = count;
573 #endif
574                         if (test > startcount) {
575                                 /* we don't need an extra rplpoint */
576                                 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
577                         }
578                         else {
579                                 count++;
580                                 alloccount += bptr->indepth;
581                                 if (bptr->inlineinfo)
582                                         alloccount -= bptr->inlineinfo->throughcount;
583
584                                 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
585                         }
586                 }
587
588         } /* end basicblock loop */
589
590         /* if no points were found, there's nothing to do */
591
592         if (!count)
593                 return true;
594
595         /* allocate replacement point array and allocation array */
596
597         rplpoints = MNEW(rplpoint, count);
598         regalloc = MNEW(rplalloc, alloccount);
599         ra = regalloc;
600
601         /* initialize replacement point structs */
602
603         rp = rplpoints;
604
605         /* XXX try to share code with the counting loop! */
606
607         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
608                 /* skip dead code */
609
610                 if (bptr->flags < BBFINISHED)
611                         continue;
612
613                 /* get info about this block */
614
615                 m = bptr->method;
616                 iinfo = bptr->inlineinfo;
617
618                 /* initialize javalocals at the start of this block */
619
620                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
621
622                 /* create replacement points at targets of backward branches */
623
624                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
625
626                         i = (iinfo) ? iinfo->throughcount : 0;
627                         replace_create_replacement_point(jd, iinfo, rp++,
628                                         bptr->type, bptr->iinstr, &ra,
629                                         bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
630
631                         if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
632                                 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
633                 }
634
635                 /* iterate over the instructions */
636
637                 iptr = bptr->iinstr;
638                 iend = iptr + bptr->icount;
639
640                 for (; iptr != iend; ++iptr) {
641                         switch (iptr->opc) {
642 #if defined(ENABLE_GC_CACAO)
643                                 case ICMD_BUILTIN:
644                                         md = iptr->sx.s23.s3.bte->md;
645
646                                         i = (iinfo) ? iinfo->throughcount : 0;
647                                         replace_create_replacement_point(jd, iinfo, rp++,
648                                                         RPLPOINT_TYPE_CALL, iptr, &ra,
649                                                         javalocals, iptr->sx.s23.s2.args,
650                                                         iptr->s1.argcount - i,
651                                                         md->paramcount);
652                                         break;
653 #endif
654
655                                 case ICMD_INVOKESTATIC:
656                                 case ICMD_INVOKESPECIAL:
657                                 case ICMD_INVOKEVIRTUAL:
658                                 case ICMD_INVOKEINTERFACE:
659                                         INSTRUCTION_GET_METHODDESC(iptr, md);
660
661                                         i = (iinfo) ? iinfo->throughcount : 0;
662                                         replace_create_replacement_point(jd, iinfo, rp++,
663                                                         RPLPOINT_TYPE_CALL, iptr, &ra,
664                                                         javalocals, iptr->sx.s23.s2.args,
665                                                         iptr->s1.argcount - i,
666                                                         md->paramcount);
667                                         break;
668
669                                 case ICMD_ISTORE:
670                                 case ICMD_LSTORE:
671                                 case ICMD_FSTORE:
672                                 case ICMD_DSTORE:
673                                 case ICMD_ASTORE:
674                                         stack_javalocals_store(iptr, javalocals);
675                                         break;
676
677                                 case ICMD_IRETURN:
678                                 case ICMD_LRETURN:
679                                 case ICMD_FRETURN:
680                                 case ICMD_DRETURN:
681                                 case ICMD_ARETURN:
682                                         replace_create_replacement_point(jd, iinfo, rp++,
683                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
684                                                         NULL, &(iptr->s1.varindex), 1, 0);
685                                         break;
686
687                                 case ICMD_RETURN:
688                                         replace_create_replacement_point(jd, iinfo, rp++,
689                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
690                                                         NULL, NULL, 0, 0);
691                                         break;
692
693                                 case ICMD_INLINE_START:
694                                         iinfo = replace_create_inline_start_replacement_point(
695                                                                 jd, rp++, iptr, &ra, javalocals);
696                                         m = iinfo->method;
697                                         /* javalocals may be set at next block start, or now */
698                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
699                                         break;
700
701                                 case ICMD_INLINE_BODY:
702                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
703
704                                         jl = iinfo->javalocals_start;
705                                         if (jl == NULL) {
706                                                 /* get the javalocals from the following block start */
707                                                 assert(bptr->next);
708                                                 jl = bptr->next->javalocals;
709                                         }
710                                         /* create a non-trappable rplpoint */
711                                         replace_create_replacement_point(jd, iinfo, rp++,
712                                                         RPLPOINT_TYPE_BODY, iptr, &ra,
713                                                         jl, NULL, 0, 0);
714                                         rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
715                                         break;
716
717                                 case ICMD_INLINE_END:
718                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
719                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
720                                         iinfo = iptr->sx.s23.s3.inlineinfo;
721                                         m = iinfo->outer;
722                                         if (iinfo->javalocals_end)
723                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
724                                         iinfo = iinfo->parent;
725                                         break;
726                         }
727                 } /* end instruction loop */
728         } /* end basicblock loop */
729
730         assert((rp - rplpoints) == count);
731         assert((ra - regalloc) == alloccount);
732
733         /* store the data in the codeinfo */
734
735         code->rplpoints     = rplpoints;
736         code->rplpointcount = count;
737         code->regalloc      = regalloc;
738         code->regalloccount = alloccount;
739         code->globalcount   = 0;
740         code->savedintcount = INT_SAV_CNT - rd->savintreguse;
741         code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
742 #if defined(HAS_ADDRESS_REGISTER_FILE)
743         code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
744 #endif
745         code->memuse        = rd->memuse;
746         code->stackframesize = jd->cd->stackframesize;
747
748         REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
749         REPLACE_COUNT_INC(stat_regallocs, alloccount);
750
751         /* everything alright */
752
753         return true;
754 }
755
756
757 /* replace_free_replacement_points *********************************************
758  
759    Free memory used by replacement points.
760   
761    IN:
762        code.............codeinfo whose replacement points should be freed.
763   
764 *******************************************************************************/
765
766 void replace_free_replacement_points(codeinfo *code)
767 {
768         assert(code);
769
770         if (code->rplpoints)
771                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
772
773         if (code->regalloc)
774                 MFREE(code->regalloc,rplalloc,code->regalloccount);
775
776         code->rplpoints = NULL;
777         code->rplpointcount = 0;
778         code->regalloc = NULL;
779         code->regalloccount = 0;
780         code->globalcount = 0;
781 }
782
783
784 /******************************************************************************/
785 /* PART II: Activating / deactivating replacement points                      */
786 /******************************************************************************/
787
788
789 /* replace_activate_replacement_points *****************************************
790  
791    Activate the replacement points of the given compilation unit. When this
792    function returns, the replacement points are "armed", so each thread
793    reaching one of the points will enter the replacement mechanism.
794    
795    IN:
796        code.............codeinfo of which replacement points should be
797                                                 activated
798            mappable.........if true, only mappable replacement points are
799                                                 activated
800   
801 *******************************************************************************/
802
803 void replace_activate_replacement_points(codeinfo *code, bool mappable)
804 {
805         rplpoint *rp;
806         s4        i;
807         s4        count;
808         u1       *savedmcode;
809
810         assert(code->savedmcode == NULL);
811
812         /* count trappable replacement points */
813
814         count = 0;
815         i = code->rplpointcount;
816         rp = code->rplpoints;
817         for (; i--; rp++) {
818                 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
819                         continue;
820
821                 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
822                         continue;
823
824                 count++;
825         }
826
827         /* allocate buffer for saved machine code */
828
829         savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
830         code->savedmcode = savedmcode;
831         savedmcode += count * REPLACEMENT_PATCH_SIZE;
832
833         /* activate trappable replacement points */
834         /* (in reverse order to handle overlapping points within basic blocks) */
835
836         i = code->rplpointcount;
837         rp = code->rplpoints + i;
838         while (rp--, i--) {
839                 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
840
841                 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
842                         continue;
843
844                 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
845                         continue;
846
847                 DOLOG( printf("activate replacement point:\n");
848                            replace_replacement_point_println(rp, 1); fflush(stdout); );
849
850                 savedmcode -= REPLACEMENT_PATCH_SIZE;
851
852 #if defined(ENABLE_JIT)
853 # if defined(ENABLE_DISASSEMBLER)
854                 DOLOG( printf("\tinstruction before: ");
855                            disassinstr(rp->pc); fflush(stdout); );
856 # endif
857
858                 md_patch_replacement_point(rp->pc, savedmcode, false);
859
860 # if defined(ENABLE_DISASSEMBLER)
861                 DOLOG( printf("\tinstruction after : ");
862                            disassinstr(rp->pc); fflush(stdout); );
863 # endif
864 #endif
865
866                 rp->flags |= RPLPOINT_FLAG_ACTIVE;
867         }
868
869         assert(savedmcode == code->savedmcode);
870 }
871
872
873 /* replace_deactivate_replacement_points ***************************************
874  
875    Deactivate a replacement points in the given compilation unit.
876    When this function returns, the replacement points will be "un-armed",
877    that is a each thread reaching a point will just continue normally.
878    
879    IN:
880        code.............the compilation unit
881   
882 *******************************************************************************/
883
884 void replace_deactivate_replacement_points(codeinfo *code)
885 {
886         rplpoint *rp;
887         s4        i;
888         s4        count;
889         u1       *savedmcode;
890
891         if (code->savedmcode == NULL) {
892                 /* disarm countdown points by patching the branches */
893
894                 i = code->rplpointcount;
895                 rp = code->rplpoints;
896                 for (; i--; rp++) {
897                         if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
898                                         == RPLPOINT_FLAG_COUNTDOWN)
899                         {
900 #if 0
901                                 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
902 #endif
903                         }
904                 }
905                 return;
906         }
907
908         assert(code->savedmcode != NULL);
909         savedmcode = code->savedmcode;
910
911         /* de-activate each trappable replacement point */
912
913         i = code->rplpointcount;
914         rp = code->rplpoints;
915         count = 0;
916         for (; i--; rp++) {
917                 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
918                         continue;
919
920                 count++;
921
922                 DOLOG( printf("deactivate replacement point:\n");
923                            replace_replacement_point_println(rp, 1); fflush(stdout); );
924
925 #if defined(ENABLE_JIT)
926 # if defined(ENABLE_DISASSEMBLER)
927                 DOLOG( printf("\tinstruction before: ");
928                            disassinstr(rp->pc); fflush(stdout); );
929 # endif
930
931                 md_patch_replacement_point(rp->pc, savedmcode, true);
932
933 # if defined(ENABLE_DISASSEMBLER)
934                 DOLOG( printf("\tinstruction before: ");
935                            disassinstr(rp->pc); fflush(stdout); );
936 # endif
937 #endif
938
939                 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
940
941                 savedmcode += REPLACEMENT_PATCH_SIZE;
942         }
943
944         assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
945
946         /* free saved machine code */
947
948         MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
949         code->savedmcode = NULL;
950 }
951
952
953 /******************************************************************************/
954 /* PART III: The replacement mechanism                                        */
955 /******************************************************************************/
956
957
958 /* replace_read_value **********************************************************
959
960    Read a value with the given allocation from the execution state.
961    
962    IN:
963            es...............execution state
964            ra...............allocation
965            javaval..........where to put the value
966
967    OUT:
968        *javaval.........the value
969   
970 *******************************************************************************/
971
972 static void replace_read_value(executionstate_t *es,
973                                                            rplalloc *ra,
974                                                            replace_val_t *javaval)
975 {
976         if (ra->flags & INMEMORY) {
977                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
978 #ifdef HAS_4BYTE_STACKSLOT
979                 if (IS_2_WORD_TYPE(ra->type)) {
980                         javaval->l = *(u8*)(es->sp + ra->regoff);
981                 }
982                 else {
983 #endif
984                         javaval->p = *(ptrint*)(es->sp + ra->regoff);
985 #ifdef HAS_4BYTE_STACKSLOT
986                 }
987 #endif
988         }
989         else {
990                 /* allocated register */
991                 if (IS_FLT_DBL_TYPE(ra->type)) {
992                         javaval->d = es->fltregs[ra->regoff];
993
994                         if (ra->type == TYPE_FLT)
995                                 javaval->f = javaval->d;
996                 }
997 #if defined(HAS_ADDRESS_REGISTER_FILE)
998                 else if (IS_ADR_TYPE(ra->type)) {
999                         javaval->p = es->adrregs[ra->regoff];
1000                 }
1001 #endif
1002                 else {
1003 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1004                         if (ra->type == TYPE_LNG) {
1005                                 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1006                                 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1007                         }
1008                         else
1009 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1010                                 javaval->p = es->intregs[ra->regoff];
1011                 }
1012         }
1013 }
1014
1015
1016 /* replace_write_value *********************************************************
1017
1018    Write a value to the given allocation in the execution state.
1019    
1020    IN:
1021            es...............execution state
1022            ra...............allocation
1023            *javaval.........the value
1024
1025 *******************************************************************************/
1026
1027 static void replace_write_value(executionstate_t *es,
1028                                                             rplalloc *ra,
1029                                                             replace_val_t *javaval)
1030 {
1031         if (ra->flags & INMEMORY) {
1032                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1033 #ifdef HAS_4BYTE_STACKSLOT
1034                 if (IS_2_WORD_TYPE(ra->type)) {
1035                         *(u8*)(es->sp + ra->regoff) = javaval->l;
1036                 }
1037                 else {
1038 #endif
1039                         *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1040 #ifdef HAS_4BYTE_STACKSLOT
1041                 }
1042 #endif
1043         }
1044         else {
1045                 /* allocated register */
1046                 switch (ra->type) {
1047                         case TYPE_FLT:
1048                                 es->fltregs[ra->regoff] = (double) javaval->f;
1049                                 break;
1050                         case TYPE_DBL:
1051                                 es->fltregs[ra->regoff] = javaval->d;
1052                                 break;
1053 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1054                         case TYPE_LNG:
1055                                 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1056                                 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1057                                 break;
1058 #endif
1059 #if defined(HAS_ADDRESS_REGISTER_FILE)
1060                         case TYPE_ADR:
1061                                 es->adrregs[ra->regoff] = javaval->p;
1062 #endif
1063                         default:
1064                                 es->intregs[ra->regoff] = javaval->p;
1065                 }
1066         }
1067 }
1068
1069
1070 /* replace_new_sourceframe *****************************************************
1071
1072    Allocate a new source frame and insert it at the front of the frame list.
1073    
1074    IN:
1075            ss...............the source state
1076
1077    OUT:
1078            ss->frames.......set to new frame (the new head of the frame list).
1079
1080    RETURN VALUE:
1081        returns the new frame
1082
1083 *******************************************************************************/
1084
1085 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1086 {
1087         sourceframe_t *frame;
1088
1089         frame = DNEW(sourceframe_t);
1090         MZERO(frame, sourceframe_t, 1);
1091
1092         frame->down = ss->frames;
1093         ss->frames = frame;
1094
1095         return frame;
1096 }
1097
1098
1099 /* replace_read_executionstate *************************************************
1100
1101    Read a source frame from the given executions state.
1102    The new source frame is pushed to the front of the frame list of the
1103    source state.
1104
1105    IN:
1106        rp...............replacement point at which `es` was taken
1107            es...............execution state
1108            ss...............the source state to add the source frame to
1109            topframe.........true, if the first (top-most) source frame on the
1110                             stack is to be read
1111
1112    OUT:
1113        *ss..............the source state with the newly created source frame
1114                             added
1115   
1116 *******************************************************************************/
1117
1118 static s4 replace_normalize_type_map[] = {
1119 /* RPLPOINT_TYPE_STD    |--> */ RPLPOINT_TYPE_STD,
1120 /* RPLPOINT_TYPE_EXH    |--> */ RPLPOINT_TYPE_STD,
1121 /* RPLPOINT_TYPE_SBR    |--> */ RPLPOINT_TYPE_STD,
1122 /* RPLPOINT_TYPE_CALL   |--> */ RPLPOINT_TYPE_CALL,
1123 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1124 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1125 /* RPLPOINT_TYPE_BODY   |--> */ RPLPOINT_TYPE_STD
1126 };
1127
1128
1129 static void replace_read_executionstate(rplpoint *rp,
1130                                                                                 executionstate_t *es,
1131                                                                                 sourcestate_t *ss,
1132                                                                                 bool topframe)
1133 {
1134         methodinfo    *m;
1135         codeinfo      *code;
1136         int            count;
1137         int            i;
1138         rplalloc      *ra;
1139         sourceframe_t *frame;
1140         int            topslot;
1141         stackslot_t   *sp;
1142         stackslot_t   *basesp;
1143
1144         code = code_find_codeinfo_for_pc(rp->pc);
1145         m = rp->method;
1146         topslot = TOP_IS_NORMAL;
1147
1148         /* stack pointer */
1149
1150         sp = (stackslot_t *) es->sp;
1151
1152         /* in some cases the top stack slot is passed in REG_ITMP1 */
1153
1154         if (rp->type == BBTYPE_EXH) {
1155                 topslot = TOP_IS_IN_ITMP1;
1156         }
1157
1158         /* calculate base stack pointer */
1159
1160         basesp = sp + code->stackframesize;
1161
1162         /* create the source frame */
1163
1164         frame = replace_new_sourceframe(ss);
1165         frame->method = rp->method;
1166         frame->id = rp->id;
1167         assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1168         frame->type = replace_normalize_type_map[rp->type];
1169         frame->fromrp = rp;
1170         frame->fromcode = code;
1171
1172         /* read local variables */
1173
1174         count = m->maxlocals;
1175         frame->javalocalcount = count;
1176         frame->javalocals = DMNEW(replace_val_t, count);
1177         frame->javalocaltype = DMNEW(u1, count);
1178
1179         /* mark values as undefined */
1180         for (i=0; i<count; ++i) {
1181 #if !defined(NDEBUG)
1182                 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1183 #endif
1184                 frame->javalocaltype[i] = TYPE_VOID;
1185         }
1186
1187         /* some entries in the intregs array are not meaningful */
1188         /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1189 #if !defined(NDEBUG)
1190         es->intregs[REG_SP   ] = (ptrint) 0x11dead1111dead11ULL;
1191 #ifdef REG_PV
1192         es->intregs[REG_PV   ] = (ptrint) 0x11dead1111dead11ULL;
1193 #endif
1194 #endif /* !defined(NDEBUG) */
1195
1196         /* read javalocals */
1197
1198         count = rp->regalloccount;
1199         ra = rp->regalloc;
1200
1201         while (count && (i = ra->index) >= 0) {
1202                 assert(i < m->maxlocals);
1203                 frame->javalocaltype[i] = ra->type;
1204                 if (ra->type == TYPE_RET)
1205                         frame->javalocals[i].i = ra->regoff;
1206                 else
1207                         replace_read_value(es, ra, frame->javalocals + i);
1208                 ra++;
1209                 count--;
1210         }
1211
1212         /* read instance, if this is the first rplpoint */
1213
1214 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1215         if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1216 #if 1
1217                 /* we are at the start of the method body, so if local 0 is set, */
1218                 /* it is the instance.                                           */
1219                 if (frame->javalocaltype[0] == TYPE_ADR)
1220                         frame->instance = frame->javalocals[0];
1221 #else
1222                 rplalloc instra;
1223                 methoddesc *md;
1224
1225                 md = rp->method->parseddesc;
1226                 assert(md->params);
1227                 assert(md->paramcount >= 1);
1228                 instra.type = TYPE_ADR;
1229                 instra.regoff = md->params[0].regoff;
1230                 if (md->params[0].inmemory) {
1231                         instra.flags = INMEMORY;
1232                         instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1233                 }
1234                 else {
1235                         instra.flags = 0;
1236                 }
1237                 replace_read_value(es, &instra, &(frame->instance));
1238 #endif
1239         }
1240 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1241
1242         /* read stack slots */
1243
1244         frame->javastackdepth = count;
1245         frame->javastack = DMNEW(replace_val_t, count);
1246         frame->javastacktype = DMNEW(u1, count);
1247
1248 #if !defined(NDEBUG)
1249         /* mark values as undefined */
1250         for (i=0; i<count; ++i) {
1251                 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1252                 frame->javastacktype[i] = TYPE_VOID;
1253         }
1254 #endif /* !defined(NDEBUG) */
1255
1256         i = 0;
1257
1258         /* the first stack slot is special in SBR and EXH blocks */
1259
1260         if (topslot == TOP_IS_ON_STACK) {
1261                 assert(count);
1262
1263                 assert(ra->index == RPLALLOC_STACK);
1264                 assert(ra->type == TYPE_ADR);
1265                 frame->javastack[i].p = sp[-1];
1266                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1267                 count--;
1268                 i++;
1269                 ra++;
1270         }
1271         else if (topslot == TOP_IS_IN_ITMP1) {
1272                 assert(count);
1273
1274                 assert(ra->index == RPLALLOC_STACK);
1275                 assert(ra->type == TYPE_ADR);
1276                 frame->javastack[i].p = es->intregs[REG_ITMP1];
1277                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1278                 count--;
1279                 i++;
1280                 ra++;
1281         }
1282         else if (topslot == TOP_IS_VOID) {
1283                 assert(count);
1284
1285                 assert(ra->index == RPLALLOC_STACK);
1286                 frame->javastack[i].l = 0;
1287                 frame->javastacktype[i] = TYPE_VOID;
1288                 count--;
1289                 i++;
1290                 ra++;
1291         }
1292
1293         /* read remaining stack slots */
1294
1295         for (; count--; ra++) {
1296                 if (ra->index == RPLALLOC_SYNC) {
1297                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1298
1299                         /* only read synchronization slots when traversing an inline point */
1300
1301                         if (!topframe) {
1302                                 sourceframe_t *calleeframe = frame->down;
1303                                 assert(calleeframe);
1304                                 assert(calleeframe->syncslotcount == 0);
1305                                 assert(calleeframe->syncslots == NULL);
1306
1307                                 calleeframe->syncslotcount = 1;
1308                                 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1309                                 replace_read_value(es,ra,calleeframe->syncslots);
1310                         }
1311
1312                         frame->javastackdepth--;
1313                         continue;
1314                 }
1315
1316                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1317
1318                 /* do not read parameters of calls down the call chain */
1319
1320                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1321                         frame->javastackdepth--;
1322                 }
1323                 else {
1324                         if (ra->type == TYPE_RET)
1325                                 frame->javastack[i].i = ra->regoff;
1326                         else
1327                                 replace_read_value(es,ra,frame->javastack + i);
1328                         frame->javastacktype[i] = ra->type;
1329                         i++;
1330                 }
1331         }
1332 }
1333
1334
1335 /* replace_write_executionstate ************************************************
1336
1337    Pop a source frame from the front of the frame list of the given source state
1338    and write its values into the execution state.
1339
1340    IN:
1341        rp...............replacement point for which execution state should be
1342                             created
1343            es...............the execution state to modify
1344            ss...............the given source state
1345            topframe.........true, if this is the last (top-most) source frame to be
1346                             translated
1347
1348    OUT:
1349        *es..............the execution state derived from the source state
1350   
1351 *******************************************************************************/
1352
1353 static void replace_write_executionstate(rplpoint *rp,
1354                                                                                  executionstate_t *es,
1355                                                                                  sourcestate_t *ss,
1356                                                                                  bool topframe)
1357 {
1358         methodinfo     *m;
1359         codeinfo       *code;
1360         int             count;
1361         int             i;
1362         rplalloc       *ra;
1363         sourceframe_t  *frame;
1364         int             topslot;
1365         stackslot_t    *sp;
1366         stackslot_t    *basesp;
1367
1368         code = code_find_codeinfo_for_pc(rp->pc);
1369         m = rp->method;
1370         topslot = TOP_IS_NORMAL;
1371
1372         /* pop a source frame */
1373
1374         frame = ss->frames;
1375         assert(frame);
1376         ss->frames = frame->down;
1377
1378         /* calculate stack pointer */
1379
1380         sp = (stackslot_t *) es->sp;
1381
1382         basesp = sp + code->stackframesize;
1383
1384         /* in some cases the top stack slot is passed in REG_ITMP1 */
1385
1386         if (rp->type == BBTYPE_EXH) {
1387                 topslot = TOP_IS_IN_ITMP1;
1388         }
1389
1390         /* write javalocals */
1391
1392         ra = rp->regalloc;
1393         count = rp->regalloccount;
1394
1395         while (count && (i = ra->index) >= 0) {
1396                 assert(i < m->maxlocals);
1397                 assert(i < frame->javalocalcount);
1398                 assert(ra->type == frame->javalocaltype[i]);
1399                 if (ra->type == TYPE_RET) {
1400                         /* XXX assert that it matches this rplpoint */
1401                 }
1402                 else
1403                         replace_write_value(es, ra, frame->javalocals + i);
1404                 count--;
1405                 ra++;
1406         }
1407
1408         /* write stack slots */
1409
1410         i = 0;
1411
1412         /* the first stack slot is special in SBR and EXH blocks */
1413
1414         if (topslot == TOP_IS_ON_STACK) {
1415                 assert(count);
1416
1417                 assert(ra->index == RPLALLOC_STACK);
1418                 assert(i < frame->javastackdepth);
1419                 assert(frame->javastacktype[i] == TYPE_ADR);
1420                 sp[-1] = frame->javastack[i].p;
1421                 count--;
1422                 i++;
1423                 ra++;
1424         }
1425         else if (topslot == TOP_IS_IN_ITMP1) {
1426                 assert(count);
1427
1428                 assert(ra->index == RPLALLOC_STACK);
1429                 assert(i < frame->javastackdepth);
1430                 assert(frame->javastacktype[i] == TYPE_ADR);
1431                 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1432                 count--;
1433                 i++;
1434                 ra++;
1435         }
1436         else if (topslot == TOP_IS_VOID) {
1437                 assert(count);
1438
1439                 assert(ra->index == RPLALLOC_STACK);
1440                 assert(i < frame->javastackdepth);
1441                 assert(frame->javastacktype[i] == TYPE_VOID);
1442                 count--;
1443                 i++;
1444                 ra++;
1445         }
1446
1447         /* write remaining stack slots */
1448
1449         for (; count--; ra++) {
1450                 if (ra->index == RPLALLOC_SYNC) {
1451                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1452
1453                         /* only write synchronization slots when traversing an inline point */
1454
1455                         if (!topframe) {
1456                                 assert(frame->down);
1457                                 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1458                                 assert(frame->down->syncslots != NULL);
1459
1460                                 replace_write_value(es,ra,frame->down->syncslots);
1461                         }
1462                         continue;
1463                 }
1464
1465                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1466
1467                 /* do not write parameters of calls down the call chain */
1468
1469                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1470                         /* skip it */
1471                 }
1472                 else {
1473                         assert(i < frame->javastackdepth);
1474                         assert(ra->type == frame->javastacktype[i]);
1475                         if (ra->type == TYPE_RET) {
1476                                 /* XXX assert that it matches this rplpoint */
1477                         }
1478                         else {
1479                                 replace_write_value(es,ra,frame->javastack + i);
1480                         }
1481                         i++;
1482                 }
1483         }
1484
1485         /* set new pc */
1486
1487         es->pc = rp->pc;
1488 }
1489
1490
1491 /* replace_pop_activation_record ***********************************************
1492
1493    Peel a stack frame from the execution state.
1494    
1495    *** This function imitates the effects of the method epilog ***
1496    *** and returning from the method call.                     ***
1497
1498    IN:
1499            es...............execution state
1500            frame............source frame, receives synchronization slots
1501
1502    OUT:
1503        *es..............the execution state after popping the stack frame
1504   
1505 *******************************************************************************/
1506
1507 u1* replace_pop_activation_record(executionstate_t *es,
1508                                                                   sourceframe_t *frame)
1509 {
1510         u1 *ra;
1511         u1 *pv;
1512         s4 reg;
1513         s4 i;
1514         s4 count;
1515         codeinfo *code;
1516         stackslot_t *basesp;
1517         stackslot_t *sp;
1518
1519         assert(es->code);
1520         assert(frame);
1521
1522         /* read the return address */
1523
1524 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1525         if (code_is_leafmethod(es->code))
1526                 ra = (u1*) (ptrint) es->intregs[REPLACE_REG_RA];
1527         else
1528 #endif
1529                 ra = md_stacktrace_get_returnaddress(es->sp,
1530                                 SIZE_OF_STACKSLOT * es->code->stackframesize);
1531
1532         DOLOG( printf("RA = %p\n", (void*)ra); );
1533
1534         assert(ra);
1535
1536         /* calculate the base of the stack frame */
1537
1538         sp = (stackslot_t *) es->sp;
1539         basesp = sp + es->code->stackframesize;
1540
1541         /* read slots used for synchronization */
1542
1543         assert(frame->syncslotcount == 0);
1544         assert(frame->syncslots == NULL);
1545         count = code_get_sync_slot_count(es->code);
1546         frame->syncslotcount = count;
1547         frame->syncslots = DMNEW(replace_val_t, count);
1548         for (i=0; i<count; ++i) {
1549                 frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX */
1550         }
1551
1552         /* restore return address, if part of frame */
1553
1554 #if defined(REPLACE_RA_TOP_OF_FRAME)
1555 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1556         if (!code_is_leafmethod(es->code))
1557 #endif
1558                 es->intregs[REPLACE_REG_RA] = *--basesp;
1559 #endif /* REPLACE_RA_TOP_OF_FRAME */
1560
1561 #if defined(REPLACE_RA_LINKAGE_AREA)
1562 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1563         if (!code_is_leafmethod(es->code))
1564 #endif
1565                 es->intregs[REPLACE_REG_RA] = basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1566 #endif /* REPLACE_RA_LINKAGE_AREA */
1567
1568         /* restore saved int registers */
1569
1570         reg = INT_REG_CNT;
1571         for (i=0; i<es->code->savedintcount; ++i) {
1572                 while (nregdescint[--reg] != REG_SAV)
1573                         ;
1574                 es->intregs[reg] = *--basesp;
1575         }
1576
1577         /* restore saved flt registers */
1578
1579         /* XXX align? */
1580         reg = FLT_REG_CNT;
1581         for (i=0; i<es->code->savedfltcount; ++i) {
1582                 while (nregdescfloat[--reg] != REG_SAV)
1583                         ;
1584                 basesp -= STACK_SLOTS_PER_FLOAT;
1585                 es->fltregs[reg] = *(double*)basesp;
1586         }
1587
1588 #if defined(HAS_ADDRESS_REGISTER_FILE)
1589         /* restore saved adr registers */
1590
1591         reg = ADR_REG_CNT;
1592         for (i=0; i<es->code->savedadrcount; ++i) {
1593                 while (nregdescadr[--reg] != REG_SAV)
1594                         ;
1595                 es->adrregs[reg] = *--basesp;
1596         }
1597 #endif
1598
1599         /* adjust the stackpointer */
1600
1601         es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1602
1603 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1604         es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1605 #endif
1606
1607         /* Set the new pc. Subtract one so we do not hit the replacement point */
1608         /* of the instruction following the call, if there is one.             */
1609
1610         es->pc = ra - 1;
1611
1612         /* find the new codeinfo */
1613
1614         pv = md_codegen_get_pv_from_pc(ra);
1615         DOLOG( printf("PV = %p\n", (void*) pv); );
1616
1617         code = code_get_codeinfo_for_pv(pv);
1618         DOLOG( printf("CODE = %p\n", (void*) code); );
1619
1620         /* return NULL if we reached native code */
1621
1622         es->pv = pv;
1623         es->code = code;
1624
1625         /* in debugging mode clobber non-saved registers */
1626
1627 #if !defined(NDEBUG)
1628         /* for debugging */
1629         for (i=0; i<INT_REG_CNT; ++i)
1630                 if ((nregdescint[i] != REG_SAV)
1631 #if defined(REG_RA)
1632                                 && (i != REPLACE_REG_RA)
1633 #endif
1634                         )
1635                         es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1636         for (i=0; i<FLT_REG_CNT; ++i)
1637                 if (nregdescfloat[i] != REG_SAV)
1638                         *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1639 # if defined(HAS_ADDRESS_REGISTER_FILE)
1640         for (i=0; i<ADR_REG_CNT; ++i)
1641                 if (nregdescadr[i] != REG_SAV)
1642                         es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1643 # endif
1644 #endif /* !defined(NDEBUG) */
1645
1646         return (code) ? ra : NULL;
1647 }
1648
1649
1650 /* replace_patch_method_pointer ************************************************
1651
1652    Patch a method pointer (may be in code, data segment, vftbl, or interface
1653    table).
1654
1655    IN:
1656            mpp..............address of the method pointer to patch
1657            entrypoint.......the new entrypoint of the method
1658            kind.............kind of call to patch, used only for debugging
1659
1660 *******************************************************************************/
1661
1662 static void replace_patch_method_pointer(methodptr *mpp,
1663                                                                                  methodptr entrypoint,
1664                                                                                  const char *kind)
1665 {
1666 #if !defined(NDEBUG)
1667         codeinfo       *oldcode;
1668         codeinfo       *newcode;
1669 #endif
1670
1671         DOLOG( printf("patch method pointer from: %p to %p\n",
1672                                   (void*) *mpp, (void*)entrypoint); );
1673
1674 #if !defined(NDEBUG)
1675         oldcode = code_get_codeinfo_for_pv(*mpp);
1676         newcode = code_get_codeinfo_for_pv(entrypoint);
1677
1678         DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
1679                                  method_println(oldcode->m);
1680                                  printf("\t      with      %p ", (void*) newcode);
1681                                  method_println(newcode->m); );
1682
1683         assert(oldcode->m == newcode->m);
1684 #endif
1685
1686         /* write the new entrypoint */
1687
1688         *mpp = (methodptr) entrypoint;
1689 }
1690
1691
1692 /* replace_patch_class *********************************************************
1693
1694    Patch a method in the given class.
1695
1696    IN:
1697            vftbl............vftbl of the class
1698            m................the method to patch
1699            oldentrypoint....the old entrypoint to replace
1700            entrypoint.......the new entrypoint
1701
1702 *******************************************************************************/
1703
1704 void replace_patch_class(vftbl_t *vftbl,
1705                                                  methodinfo *m,
1706                                                  u1 *oldentrypoint,
1707                                                  u1 *entrypoint)
1708 {
1709         s4                 i;
1710         methodptr         *mpp;
1711         methodptr         *mppend;
1712
1713         /* patch the vftbl of the class */
1714
1715         replace_patch_method_pointer(vftbl->table + m->vftblindex,
1716                                                                  entrypoint,
1717                                                                  "virtual  ");
1718
1719         /* patch the interface tables */
1720
1721         assert(oldentrypoint);
1722
1723         for (i=0; i < vftbl->interfacetablelength; ++i) {
1724                 mpp = vftbl->interfacetable[-i];
1725                 mppend = mpp + vftbl->interfacevftbllength[i];
1726                 for (; mpp != mppend; ++mpp)
1727                         if (*mpp == oldentrypoint) {
1728                                 replace_patch_method_pointer(mpp, entrypoint, "interface");
1729                         }
1730         }
1731 }
1732
1733
1734 /* replace_patch_class_hierarchy ***********************************************
1735
1736    Patch a method in all loaded classes.
1737
1738    IN:
1739            m................the method to patch
1740            oldentrypoint....the old entrypoint to replace
1741            entrypoint.......the new entrypoint
1742
1743 *******************************************************************************/
1744
1745 struct replace_patch_data_t {
1746         methodinfo *m;
1747         u1         *oldentrypoint;
1748         u1         *entrypoint;
1749 };
1750
1751 void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
1752 {
1753         vftbl_t *vftbl = c->vftbl;
1754
1755         if (vftbl != NULL
1756                 && vftbl->vftbllength > pd->m->vftblindex
1757                 && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
1758                 && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
1759         {
1760                 replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
1761         }
1762 }
1763
1764 void replace_patch_class_hierarchy(methodinfo *m,
1765                                                                    u1 *oldentrypoint,
1766                                                                    u1 *entrypoint)
1767 {
1768         struct replace_patch_data_t pd;
1769
1770         pd.m = m;
1771         pd.oldentrypoint = oldentrypoint;
1772         pd.entrypoint = entrypoint;
1773
1774         DOLOG_SHORT( printf("patching class hierarchy: ");
1775                              method_println(m); );
1776
1777         classcache_foreach_loaded_class(
1778                         (classcache_foreach_functionptr_t) &replace_patch_callback,
1779                         (void*) &pd);
1780 }
1781
1782
1783 /* replace_patch_future_calls **************************************************
1784
1785    Analyse a call site and depending on the kind of call patch the call, the
1786    virtual function table, or the interface table.
1787
1788    IN:
1789            ra...............return address pointing after the call site
1790            callerframe......source frame of the caller
1791            calleeframe......source frame of the callee, must have been mapped
1792
1793 *******************************************************************************/
1794
1795 void replace_patch_future_calls(u1 *ra,
1796                                                                 sourceframe_t *callerframe,
1797                                                                 sourceframe_t *calleeframe)
1798 {
1799         u1            *patchpos;
1800         methodptr      entrypoint;
1801         methodptr      oldentrypoint;
1802         bool           atentry;
1803         void          *pv;
1804         codeinfo      *calleecode;
1805         methodinfo    *calleem;
1806         java_object_t *obj;
1807         vftbl_t       *vftbl;
1808
1809         assert(ra);
1810         assert(callerframe->down == calleeframe);
1811
1812         /* get the new codeinfo and the method that shall be entered */
1813
1814         calleecode = calleeframe->tocode;
1815         assert(calleecode);
1816
1817         calleem = calleeframe->method;
1818         assert(calleem == calleecode->m);
1819
1820         entrypoint = (methodptr) calleecode->entrypoint;
1821
1822         /* check if we are at an method entry rplpoint at the innermost frame */
1823
1824         atentry = (calleeframe->down == NULL)
1825                         && !(calleem->flags & ACC_STATIC)
1826                         && (calleeframe->fromrp->id == 0); /* XXX */
1827
1828         /* get the position to patch, in case it was a statically bound call   */
1829
1830         pv = callerframe->fromcode->entrypoint;
1831         patchpos = md_jit_method_patch_address(pv, ra, NULL);
1832
1833         if (patchpos == NULL) {
1834                 /* the call was dispatched dynamically */
1835
1836                 /* we can only patch such calls if we are at the entry point */
1837
1838                 if (!atentry)
1839                         return;
1840
1841                 assert((calleem->flags & ACC_STATIC) == 0);
1842
1843                 oldentrypoint = calleeframe->fromcode->entrypoint;
1844
1845                 /* we need to know the instance */
1846
1847                 if (!calleeframe->instance.a) {
1848                         DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
1849                         replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
1850                         return;
1851                 }
1852
1853                 /* get the vftbl */
1854
1855                 obj = calleeframe->instance.a;
1856                 vftbl = obj->vftbl;
1857
1858                 assert(vftbl->class->vftbl == vftbl);
1859
1860                 DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
1861
1862                 replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
1863         }
1864         else {
1865                 /* the call was statically bound */
1866
1867                 replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static   ");
1868         }
1869 }
1870
1871
1872 /* replace_push_activation_record **********************************************
1873
1874    Push a stack frame onto the execution state.
1875    
1876    *** This function imitates the effects of a call and the ***
1877    *** method prolog of the callee.                         ***
1878
1879    IN:
1880            es...............execution state
1881            rpcall...........the replacement point at the call site
1882            callerframe......source frame of the caller, or NULL for creating the
1883                             first frame
1884            calleeframe......source frame of the callee, must have been mapped
1885
1886    OUT:
1887        *es..............the execution state after pushing the stack frame
1888   
1889 *******************************************************************************/
1890
1891 void replace_push_activation_record(executionstate_t *es,
1892                                                                         rplpoint *rpcall,
1893                                                                         sourceframe_t *callerframe,
1894                                                                         sourceframe_t *calleeframe)
1895 {
1896         s4           reg;
1897         s4           i;
1898         s4           count;
1899         stackslot_t *basesp;
1900         stackslot_t *sp;
1901         u1          *ra;
1902         codeinfo    *calleecode;
1903
1904         assert(es);
1905         assert(!rpcall || callerframe);
1906     assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
1907         assert(!rpcall || rpcall == callerframe->torp);
1908         assert(calleeframe);
1909         assert(!callerframe || calleeframe == callerframe->down);
1910
1911         /* the compilation unit we are entering */
1912
1913         calleecode = calleeframe->tocode;
1914         assert(calleecode);
1915
1916         /* calculate the return address */
1917
1918         if (rpcall)
1919                 ra = rpcall->pc + rpcall->callsize;
1920         else
1921                 ra = es->pc + 1 /* XXX this is ugly */;
1922
1923         /* write the return address */
1924
1925 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1926         es->sp -= SIZE_OF_STACKSLOT;
1927
1928         *((stackslot_t *)es->sp) = (stackslot_t) ra;
1929 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1930
1931 #if defined(REPLACE_REG_RA)
1932         es->intregs[REPLACE_REG_RA] = (ptrint) ra;
1933 #endif
1934
1935         /* we move into a new code unit */
1936
1937         es->code = calleecode;
1938
1939         /* set the new pc XXX not needed? */
1940
1941         es->pc = calleecode->entrypoint;
1942
1943         /* build the stackframe */
1944
1945         DOLOG( printf("building stackframe of %d words at %p\n",
1946                                   calleecode->stackframesize, (void*)es->sp); );
1947
1948         sp = (stackslot_t *) es->sp;
1949         basesp = sp;
1950
1951         sp -= calleecode->stackframesize;
1952         es->sp = (u1*) sp;
1953
1954         /* in debug mode, invalidate stack frame first */
1955
1956         /* XXX may not invalidate linkage area used by native code! */
1957 #if !defined(NDEBUG) && 0
1958         for (i=0; i<(basesp - sp); ++i) {
1959                 sp[i] = 0xdeaddeadU;
1960         }
1961 #endif
1962
1963         /* save the return address register */
1964
1965 #if defined(REPLACE_RA_TOP_OF_FRAME)
1966 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1967         if (!code_is_leafmethod(calleecode))
1968 #endif
1969                 *--basesp = (ptrint) ra;
1970 #endif /* REPLACE_RA_TOP_OF_FRAME */
1971
1972 #if defined(REPLACE_RA_LINKAGE_AREA)
1973 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1974         if (!code_is_leafmethod(calleecode))
1975 #endif
1976                 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1977 #endif /* REPLACE_RA_LINKAGE_AREA */
1978
1979         /* save int registers */
1980
1981         reg = INT_REG_CNT;
1982         for (i=0; i<calleecode->savedintcount; ++i) {
1983                 while (nregdescint[--reg] != REG_SAV)
1984                         ;
1985                 *--basesp = es->intregs[reg];
1986
1987                 /* XXX may not clobber saved regs used by native code! */
1988 #if !defined(NDEBUG) && 0
1989                 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1990 #endif
1991         }
1992
1993         /* save flt registers */
1994
1995         /* XXX align? */
1996         reg = FLT_REG_CNT;
1997         for (i=0; i<calleecode->savedfltcount; ++i) {
1998                 while (nregdescfloat[--reg] != REG_SAV)
1999                         ;
2000                 basesp -= STACK_SLOTS_PER_FLOAT;
2001                 *(double*)basesp = es->fltregs[reg];
2002
2003                 /* XXX may not clobber saved regs used by native code! */
2004 #if !defined(NDEBUG) && 0
2005                 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
2006 #endif
2007         }
2008
2009 #if defined(HAS_ADDRESS_REGISTER_FILE)
2010         /* save adr registers */
2011
2012         reg = ADR_REG_CNT;
2013         for (i=0; i<calleecode->savedadrcount; ++i) {
2014                 while (nregdescadr[--reg] != REG_SAV)
2015                         ;
2016                 *--basesp = es->adrregs[reg];
2017
2018                 /* XXX may not clobber saved regs used by native code! */
2019 #if !defined(NDEBUG) && 0
2020                 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
2021 #endif
2022         }
2023 #endif
2024
2025         /* write slots used for synchronization */
2026
2027         count = code_get_sync_slot_count(calleecode);
2028         assert(count == calleeframe->syncslotcount);
2029         for (i=0; i<count; ++i) {
2030                 sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
2031         }
2032
2033         /* set the PV */
2034
2035         es->pv = calleecode->entrypoint;
2036
2037         /* redirect future invocations */
2038
2039         if (callerframe && rpcall) {
2040 #if defined(REPLACE_PATCH_ALL)
2041                 if (rpcall->type == callerframe->fromrp->type)
2042 #else
2043                 if (rpcall == callerframe->fromrp)
2044 #endif
2045                         replace_patch_future_calls(ra, callerframe, calleeframe);
2046         }
2047 }
2048
2049
2050 /* replace_find_replacement_point **********************************************
2051
2052    Find the replacement point in the given code corresponding to the
2053    position given in the source frame.
2054    
2055    IN:
2056            code.............the codeinfo in which to search the rplpoint
2057            frame............the source frame defining the position to look for
2058            parent...........parent replacement point to match
2059
2060    RETURN VALUE:
2061        the replacement point
2062   
2063 *******************************************************************************/
2064
2065 rplpoint * replace_find_replacement_point(codeinfo *code,
2066                                                                                   sourceframe_t *frame,
2067                                                                                   rplpoint *parent)
2068 {
2069         methodinfo *m;
2070         rplpoint *rp;
2071         s4        i;
2072         s4        j;
2073         s4        stacki;
2074         rplalloc *ra;
2075
2076         assert(code);
2077         assert(frame);
2078
2079         DOLOG( printf("searching replacement point for:\n");
2080                    replace_source_frame_println(frame); );
2081
2082         m = frame->method;
2083
2084         DOLOG( printf("code = %p\n", (void*)code); );
2085
2086         rp = code->rplpoints;
2087         i = code->rplpointcount;
2088         while (i--) {
2089                 if (rp->id == frame->id && rp->method == frame->method
2090                                 && rp->parent == parent
2091                                 && replace_normalize_type_map[rp->type] == frame->type)
2092                 {
2093                         /* check if returnAddresses match */
2094                         /* XXX optimize: only do this if JSRs in method */
2095                         DOLOG( printf("checking match for:");
2096                                    replace_replacement_point_println(rp, 1); fflush(stdout); );
2097                         ra = rp->regalloc;
2098                         stacki = 0;
2099                         for (j = rp->regalloccount; j--; ++ra) {
2100                                 if (ra->type == TYPE_RET) {
2101                                         if (ra->index == RPLALLOC_STACK) {
2102                                                 assert(stacki < frame->javastackdepth);
2103                                                 if (frame->javastack[stacki].i != ra->regoff)
2104                                                         goto no_match;
2105                                                 stacki++;
2106                                         }
2107                                         else {
2108                                                 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
2109                                                 if (frame->javalocals[ra->index].i != ra->regoff)
2110                                                         goto no_match;
2111                                         }
2112                                 }
2113                         }
2114
2115                         /* found */
2116                         return rp;
2117                 }
2118 no_match:
2119                 rp++;
2120         }
2121
2122 #if !defined(NDEBUG)
2123         printf("candidate replacement points were:\n");
2124         rp = code->rplpoints;
2125         i = code->rplpointcount;
2126         for (; i--; ++rp) {
2127                 replace_replacement_point_println(rp, 1);
2128         }
2129 #endif
2130
2131         vm_abort("no matching replacement point found");
2132         return NULL; /* NOT REACHED */
2133 }
2134
2135
2136 /* replace_find_replacement_point_for_pc ***************************************
2137
2138    Find the nearest replacement point at or before the given PC. The
2139    given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
2140    the replacement point to be found.
2141
2142    IN:
2143        code.............compilation unit the PC is in
2144            pc...............the machine code PC
2145
2146    RETURN VALUE:
2147        the replacement point found, or
2148            NULL if no replacement point was found
2149
2150 *******************************************************************************/
2151
2152 rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
2153 {
2154         rplpoint *found;
2155         rplpoint *rp;
2156         s4        i;
2157
2158         DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
2159                    method_println(code->m); );
2160
2161         found = NULL;
2162
2163         rp = code->rplpoints;
2164         for (i=0; i<code->rplpointcount; ++i, ++rp) {
2165                 DOLOG( replace_replacement_point_println(rp, 2); );
2166                 if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
2167                         found = rp;
2168         }
2169
2170         return found;
2171 }
2172
2173
2174 /* replace_pop_native_frame ****************************************************
2175
2176    Unroll a native frame in the execution state and create a source frame
2177    for it.
2178
2179    IN:
2180            es...............current execution state
2181            ss...............the current source state
2182            sfi..............stackframeinfo for the native frame
2183
2184    OUT:
2185        es...............execution state after unrolling the native frame
2186            ss...............gets the added native source frame
2187
2188 *******************************************************************************/
2189
2190 static void replace_pop_native_frame(executionstate_t *es,
2191                                                                          sourcestate_t *ss,
2192                                                                          stackframeinfo *sfi)
2193 {
2194         sourceframe_t *frame;
2195         codeinfo      *code;
2196         s4             i,j;
2197
2198         assert(sfi);
2199
2200         frame = replace_new_sourceframe(ss);
2201
2202         frame->sfi = sfi;
2203
2204         /* remember pc and size of native frame */
2205
2206         frame->nativepc = es->pc;
2207         frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
2208         assert(frame->nativeframesize >= 0);
2209
2210         /* remember values of saved registers */
2211
2212         j = 0;
2213         for (i=0; i<INT_REG_CNT; ++i) {
2214                 if (nregdescint[i] == REG_SAV)
2215                         frame->nativesavint[j++] = es->intregs[i];
2216         }
2217
2218         j = 0;
2219         for (i=0; i<FLT_REG_CNT; ++i) {
2220                 if (nregdescfloat[i] == REG_SAV)
2221                         frame->nativesavflt[j++] = es->fltregs[i];
2222         }
2223
2224 #if defined(HAS_ADDRESS_REGISTER_FILE)
2225         j = 0;
2226         for (i=0; i<ADR_REG_CNT; ++i) {
2227                 if (nregdescadr[i] == REG_SAV)
2228                         frame->nativesavadr[j++] = es->adrregs[i];
2229         }
2230 #endif
2231
2232         /* restore saved registers */
2233
2234 #if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
2235         j = 0;
2236         for (i=0; i<INT_REG_CNT; ++i) {
2237                 if (nregdescint[i] == REG_SAV)
2238                         es->intregs[i] = sfi->intregs[j++];
2239         }
2240 #else
2241         /* XXX we don't have them, yet, in the sfi, so clear them */
2242
2243         for (i=0; i<INT_REG_CNT; ++i) {
2244                 if (nregdescint[i] == REG_SAV)
2245                         es->intregs[i] = 0;
2246         }
2247 #endif
2248
2249         /* XXX we don't have float registers in the sfi, so clear them */
2250
2251         for (i=0; i<FLT_REG_CNT; ++i) {
2252                 if (nregdescfloat[i] == REG_SAV)
2253                         es->fltregs[i] = 0.0;
2254         }
2255
2256 #if defined(HAS_ADDRESS_REGISTER_FILE)
2257 # if defined(ENABLE_GC_CACAO)
2258         j = 0;
2259         for (i=0; i<ADR_REG_CNT; ++i) {
2260                 if (nregdescadr[i] == REG_SAV)
2261                         es->adrregs[i] = sfi->adrregs[j++];
2262         }
2263 # else
2264         for (i=0; i<ADR_REG_CNT; ++i) {
2265                 if (nregdescadr[i] == REG_SAV)
2266                         es->adrregs[i] = 0;
2267         }
2268 # endif
2269 #endif
2270
2271         /* restore codeinfo of the native stub */
2272
2273         code = code_get_codeinfo_for_pv(sfi->pv);
2274
2275         /* restore sp, pv, pc and codeinfo of the parent method */
2276
2277         /* XXX michi: use this instead:
2278         es->sp = sfi->sp + code->stackframesize; */
2279         es->sp   = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
2280 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2281         es->sp  += SIZE_OF_STACKSLOT; /* skip return address */
2282 #endif
2283         es->pv   = md_codegen_get_pv_from_pc(sfi->ra);
2284         es->pc   = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
2285         es->code = code_get_codeinfo_for_pv(es->pv);
2286 }
2287
2288
2289 /* replace_push_native_frame ***************************************************
2290
2291    Rebuild a native frame onto the execution state and remove its source frame.
2292
2293    Note: The native frame is "rebuild" by setting fields like PC and stack
2294          pointer in the execution state accordingly. Values in the
2295                  stackframeinfo may be modified, but the actual stack frame of the
2296                  native code is not touched.
2297
2298    IN:
2299            es...............current execution state
2300            ss...............the current source state
2301
2302    OUT:
2303        es...............execution state after re-rolling the native frame
2304            ss...............the native source frame is removed
2305
2306 *******************************************************************************/
2307
2308 static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
2309 {
2310         sourceframe_t *frame;
2311         s4             i,j;
2312
2313         assert(es);
2314         assert(ss);
2315
2316         DOLOG( printf("pushing native frame\n"); );
2317
2318         /* remove the frame from the source state */
2319
2320         frame = ss->frames;
2321         assert(frame);
2322         assert(REPLACE_IS_NATIVE_FRAME(frame));
2323
2324         ss->frames = frame->down;
2325
2326         /* skip sp for the native stub */
2327
2328         es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
2329 #if defined(REPLACE_RA_BETWEEN_FRAMES)
2330         es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
2331 #endif
2332
2333         /* assert that the native frame has not moved */
2334
2335         assert(es->sp == frame->sfi->sp);
2336
2337         /* update saved registers in the stackframeinfo */
2338
2339 #if defined(ENABLE_GC_CACAO)
2340         j = 0;
2341 # if !defined(HAS_ADDRESS_REGISTER_FILE)
2342         for (i=0; i<INT_REG_CNT; ++i) {
2343                 if (nregdescint[i] == REG_SAV)
2344                         frame->sfi->intregs[j++] = es->intregs[i];
2345         }
2346 # else
2347         for (i=0; i<ADR_REG_CNT; ++i) {
2348                 if (nregdescadr[i] == REG_SAV)
2349                         frame->sfi->adrregs[j++] = es->adrregs[i];
2350         }
2351 # endif
2352
2353         /* XXX leave float registers untouched here */
2354 #endif
2355
2356         /* restore saved registers */
2357
2358         j = 0;
2359         for (i=0; i<INT_REG_CNT; ++i) {
2360                 if (nregdescint[i] == REG_SAV)
2361                         es->intregs[i] = frame->nativesavint[j++];
2362         }
2363
2364         j = 0;
2365         for (i=0; i<FLT_REG_CNT; ++i) {
2366                 if (nregdescfloat[i] == REG_SAV)
2367                         es->fltregs[i] = frame->nativesavflt[j++];
2368         }
2369
2370 #if defined(HAS_ADDRESS_REGISTER_FILE)
2371         j = 0;
2372         for (i=0; i<ADR_REG_CNT; ++i) {
2373                 if (nregdescadr[i] == REG_SAV)
2374                         es->adrregs[i] = frame->nativesavadr[j++];
2375         }
2376 #endif
2377
2378         /* skip the native frame on the machine stack */
2379
2380         es->sp -= frame->nativeframesize;
2381
2382         /* set the pc the next frame must return to */
2383
2384         es->pc = frame->nativepc;
2385 }
2386
2387
2388 /* replace_recover_source_state ************************************************
2389
2390    Recover the source state from the given replacement point and execution
2391    state.
2392
2393    IN:
2394        rp...............replacement point that has been reached, if any
2395            sfi..............stackframeinfo, if called from native code
2396            es...............execution state at the replacement point rp
2397
2398    RETURN VALUE:
2399        the source state
2400
2401 *******************************************************************************/
2402
2403 sourcestate_t *replace_recover_source_state(rplpoint *rp,
2404                                                                                         stackframeinfo *sfi,
2405                                                                                     executionstate_t *es)
2406 {
2407         sourcestate_t *ss;
2408         u1            *ra;
2409         bool           locked;
2410 #if defined(REPLACE_STATISTICS)
2411         s4             depth;
2412 #endif
2413
2414         /* create the source frame structure in dump memory */
2415
2416         ss = DNEW(sourcestate_t);
2417         ss->frames = NULL;
2418
2419         /* each iteration of the loop recovers one source frame */
2420
2421         depth = 0;
2422         locked = false;
2423
2424         while (rp || sfi) {
2425
2426                 DOLOG( replace_executionstate_println(es); );
2427
2428                 /* if we are not at a replacement point, it is a native frame */
2429
2430                 if (rp == NULL) {
2431                         DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
2432
2433                         locked = true;
2434                         replace_pop_native_frame(es, ss, sfi);
2435                         sfi = sfi->prev;
2436
2437                         if (es->code == NULL)
2438                                 continue;
2439
2440                         goto after_machine_frame;
2441                 }
2442
2443                 /* read the values for this source frame from the execution state */
2444
2445                 DOLOG( printf("recovering source state for%s:\n",
2446                                         (ss->frames == NULL) ? " TOPFRAME" : "");
2447                            replace_replacement_point_println(rp, 1); );
2448
2449                 replace_read_executionstate(rp, es, ss, ss->frames == NULL);
2450
2451 #if defined(ENABLE_VMLOG)
2452                 vmlog_cacao_unrol_method(ss->frames->method);
2453 #endif
2454
2455 #if defined(REPLACE_STATISTICS)
2456                 REPLACE_COUNT(stat_frames);
2457                 depth++;
2458                 replace_statistics_source_frame(ss->frames);
2459 #endif
2460
2461                 /* in locked areas (below native frames), identity map the frame */
2462
2463                 if (locked) {
2464                         ss->frames->torp = ss->frames->fromrp;
2465                         ss->frames->tocode = ss->frames->fromcode;
2466                 }
2467
2468                 /* unroll to the next (outer) frame */
2469
2470                 if (rp->parent) {
2471                         /* this frame is in inlined code */
2472
2473                         DOLOG( printf("INLINED!\n"); );
2474
2475                         rp = rp->parent;
2476
2477                         assert(rp->type == RPLPOINT_TYPE_INLINE);
2478                         REPLACE_COUNT(stat_unroll_inline);
2479                 }
2480                 else {
2481                         /* this frame had been called at machine-level. pop it. */
2482
2483                         DOLOG( printf("UNWIND\n"); );
2484
2485                         ra = replace_pop_activation_record(es, ss->frames);
2486                         if (ra == NULL) {
2487                                 DOLOG( printf("REACHED NATIVE CODE\n"); );
2488
2489                                 rp = NULL;
2490
2491 #if !defined(ENABLE_GC_CACAO)
2492                                 break; /* XXX remove to activate native frames */
2493 #endif
2494                                 continue;
2495                         }
2496
2497                         /* find the replacement point at the call site */
2498
2499 after_machine_frame:
2500                         rp = replace_find_replacement_point_for_pc(es->code, es->pc);
2501
2502                         if (rp == NULL)
2503                                 vm_abort("could not find replacement point while unrolling call");
2504
2505                         DOLOG( printf("found replacement point.\n");
2506                                         replace_replacement_point_println(rp, 1); );
2507
2508                         assert(rp->type == RPLPOINT_TYPE_CALL);
2509                         REPLACE_COUNT(stat_unroll_call);
2510                 }
2511         } /* end loop over source frames */
2512
2513         REPLACE_COUNT_DIST(stat_dist_frames, depth);
2514
2515         return ss;
2516 }
2517
2518
2519 /* replace_map_source_state ****************************************************
2520
2521    Map each source frame in the given source state to a target replacement
2522    point and compilation unit. If no valid code is available for a source
2523    frame, it is (re)compiled.
2524
2525    IN:
2526        ss...............the source state
2527
2528    OUT:
2529        ss...............the source state, modified: The `torp` and `tocode`
2530                             fields of each source frame are set.
2531
2532    RETURN VALUE:
2533        true.............everything went ok
2534            false............an exception has been thrown
2535
2536 *******************************************************************************/
2537
2538 static bool replace_map_source_state(sourcestate_t *ss)
2539 {
2540         sourceframe_t *frame;
2541         codeinfo      *code;
2542         rplpoint      *rp;
2543         rplpoint      *parent; /* parent of inlined rplpoint */
2544 #if defined(REPLACE_STATISTICS)
2545         codeinfo      *oldcode;
2546 #endif
2547
2548         parent = NULL;
2549         code = NULL;
2550
2551         /* iterate over the source frames from outermost to innermost */
2552
2553         for (frame = ss->frames; frame != NULL; frame = frame->down) {
2554
2555                 /* XXX skip native frames */
2556
2557                 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2558                         parent = NULL;
2559                         continue;
2560                 }
2561
2562                 /* map frames which are not already mapped */
2563
2564                 if (frame->tocode) {
2565                         code = frame->tocode;
2566                         rp = frame->torp;
2567                         assert(rp);
2568                 }
2569                 else {
2570                         assert(frame->torp == NULL);
2571
2572                         if (parent == NULL) {
2573                                 /* find code for this frame */
2574
2575 #if defined(REPLACE_STATISTICS)
2576                                 oldcode = frame->method->code;
2577 #endif
2578                                 /* request optimization of hot methods and their callers */
2579
2580                                 if (frame->method->hitcountdown < 0
2581                                         || (frame->down && frame->down->method->hitcountdown < 0))
2582                                         jit_request_optimization(frame->method);
2583
2584                                 code = jit_get_current_code(frame->method);
2585
2586                                 if (code == NULL)
2587                                         return false; /* exception */
2588
2589                                 REPLACE_COUNT_IF(stat_recompile, code != oldcode);
2590                         }
2591
2592                         assert(code);
2593
2594                         /* map this frame */
2595
2596                         rp = replace_find_replacement_point(code, frame, parent);
2597
2598                         frame->tocode = code;
2599                         frame->torp = rp;
2600                 }
2601
2602                 if (rp->type == RPLPOINT_TYPE_CALL) {
2603                         parent = NULL;
2604                 }
2605                 else {
2606                         /* inlining */
2607                         parent = rp;
2608                 }
2609         }
2610
2611         return true;
2612 }
2613
2614
2615 /* replace_map_source_state_identity *******************************************
2616
2617    Map each source frame in the given source state to the same replacement
2618    point and compilation unit it was derived from. This is mainly used for
2619    garbage collection.
2620
2621    IN:
2622        ss...............the source state
2623
2624    OUT:
2625        ss...............the source state, modified: The `torp` and `tocode`
2626                             fields of each source frame are set.
2627
2628 *******************************************************************************/
2629
2630 #if defined(ENABLE_GC_CACAO)
2631 static void replace_map_source_state_identity(sourcestate_t *ss)
2632 {
2633         sourceframe_t *frame;
2634
2635         /* iterate over the source frames from outermost to innermost */
2636
2637         for (frame = ss->frames; frame != NULL; frame = frame->down) {
2638
2639                 /* skip native frames */
2640
2641                 if (REPLACE_IS_NATIVE_FRAME(frame)) {
2642                         continue;
2643                 }
2644
2645                 /* map frames using the identity mapping */
2646
2647                 if (frame->tocode) {
2648                         assert(frame->tocode == frame->fromcode);
2649                         assert(frame->torp   == frame->fromrp);
2650                 } else {
2651                         assert(frame->tocode == NULL);
2652                         assert(frame->torp   == NULL);
2653                         frame->tocode = frame->fromcode;
2654                         frame->torp   = frame->fromrp;
2655                 }
2656         }
2657 }
2658 #endif
2659
2660
2661 /* replace_build_execution_state ***********************************************
2662
2663    Build an execution state for the given (mapped) source state.
2664
2665    !!! CAUTION: This function rewrites the machine stack !!!
2666
2667    THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2668
2669    IN:
2670        ss...............the source state. Must have been mapped by
2671                                                 replace_map_source_state before.
2672            es...............the base execution state on which to build
2673
2674    OUT:
2675        *es..............the new execution state
2676
2677 *******************************************************************************/
2678
2679 static void replace_build_execution_state(sourcestate_t *ss,
2680                                                                                   executionstate_t *es)
2681 {
2682         rplpoint      *rp;
2683         sourceframe_t *prevframe;
2684         rplpoint      *parent;
2685
2686         parent = NULL;
2687         prevframe = NULL;
2688         rp = NULL;
2689
2690         while (ss->frames) {
2691
2692                 if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
2693                         prevframe = ss->frames;
2694                         replace_push_native_frame(es, ss);
2695                         parent = NULL;
2696                         rp = NULL;
2697                         continue;
2698                 }
2699
2700                 if (parent == NULL) {
2701                         /* create a machine-level stack frame */
2702
2703                         DOLOG( printf("pushing activation record for:\n");
2704                                    if (rp) replace_replacement_point_println(rp, 1);
2705                                    else printf("\tfirst frame\n"); );
2706
2707                         replace_push_activation_record(es, rp, prevframe, ss->frames);
2708
2709                         DOLOG( replace_executionstate_println(es); );
2710                 }
2711
2712                 rp = ss->frames->torp;
2713                 assert(rp);
2714
2715                 DOLOG( printf("creating execution state for%s:\n",
2716                                 (ss->frames->down == NULL) ? " TOPFRAME" : "");
2717                            replace_replacement_point_println(ss->frames->fromrp, 1);
2718                            replace_replacement_point_println(rp, 1); );
2719
2720                 es->code = ss->frames->tocode;
2721                 prevframe = ss->frames;
2722
2723 #if defined(ENABLE_VMLOG)
2724                 vmlog_cacao_rerol_method(ss->frames->method);
2725 #endif
2726
2727                 replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
2728
2729                 DOLOG( replace_executionstate_println(es); );
2730
2731                 if (rp->type == RPLPOINT_TYPE_CALL) {
2732                         parent = NULL;
2733                 }
2734                 else {
2735                         /* inlining */
2736                         parent = rp;
2737                 }
2738         }
2739 }
2740
2741
2742 /* replace_me ******************************************************************
2743  
2744    This function is called by the signal handler when a thread reaches
2745    a replacement point. `replace_me` must map the execution state to the
2746    target replacement point and let execution continue there.
2747
2748    THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2749
2750    IN:
2751        rp...............replacement point that has been reached
2752        es...............execution state read by signal handler
2753   
2754 *******************************************************************************/
2755
2756 static void replace_me(rplpoint *rp, executionstate_t *es)
2757 {
2758         stackframeinfo      *sfi;
2759         sourcestate_t       *ss;
2760         sourceframe_t       *frame;
2761         s4                   dumpsize;
2762         codeinfo            *origcode;
2763         rplpoint            *origrp;
2764 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2765         threadobject        *thread;
2766 #endif
2767
2768         origcode = es->code;
2769         origrp   = rp;
2770
2771         DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2772                                  stat_replacements, (void*)THREADOBJECT,
2773                                  rp->id, (void*)rp);
2774                                  method_println(es->code->m); );
2775
2776         DOLOG( replace_replacement_point_println(rp, 1); );
2777
2778         REPLACE_COUNT(stat_replacements);
2779
2780         /* mark start of dump memory area */
2781
2782         dumpsize = dump_size();
2783
2784         /* get the stackframeinfo for the current thread */
2785
2786         sfi = STACKFRAMEINFO;
2787
2788         /* recover source state */
2789
2790         ss = replace_recover_source_state(rp, sfi, es);
2791
2792 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2793         /* if there is a collection pending, we assume the replacement point should
2794            suspend this thread */
2795
2796         if (gc_pending) {
2797
2798                 thread = THREADOBJECT;
2799
2800                 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2801
2802                 /* map the sourcestate using the identity mapping */
2803                 replace_map_source_state_identity(ss);
2804
2805                 /* since we enter the same method again, we turn off rps now */
2806                 /* XXX michi: can we really do this? what if the rp was active before
2807                    we activated it for the gc? */
2808                 replace_deactivate_replacement_points(origcode);
2809
2810                 /* remember executionstate and sourcestate for this thread */
2811                 GC_EXECUTIONSTATE = es;
2812                 GC_SOURCESTATE    = ss;
2813
2814                 /* really suspend this thread now (PC = 0) */
2815                 threads_suspend_ack(NULL, NULL);
2816
2817                 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2818
2819         } else {
2820 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2821
2822         /* map the source state */
2823
2824         if (!replace_map_source_state(ss))
2825                 vm_abort("exception during method replacement");
2826
2827         DOLOG( replace_sourcestate_println(ss); );
2828
2829         DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2830
2831 #if !defined(NDEBUG)
2832         /* avoid infinite loops by self-replacement, only if not in testing mode */
2833
2834         if (!opt_TestReplacement) {
2835                 frame = ss->frames;
2836                 while (frame->down)
2837                         frame = frame->down;
2838
2839                 if (frame->torp == origrp) {
2840                         DOLOG_SHORT(
2841                                 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2842                         );
2843                         replace_deactivate_replacement_points(origcode);
2844                 }
2845         }
2846 #endif
2847
2848 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2849         }
2850 #endif
2851
2852         /* build the new execution state */
2853
2854         replace_build_execution_state(ss, es);
2855
2856 #if !defined(NDEBUG)
2857         /* continue execution after patched machine code, if testing mode enabled */
2858
2859         if (opt_TestReplacement)
2860                 es->pc += REPLACEMENT_PATCH_SIZE;
2861 #endif
2862
2863         /* release dump area */
2864
2865         dump_release(dumpsize);
2866 }
2867
2868
2869 /* replace_me_wrapper **********************************************************
2870
2871    This function is called by the signal handler. It determines if there
2872    is an active replacement point pending at the given PC and returns
2873    accordingly.
2874
2875    THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2876
2877    IN:
2878        pc...............the program counter that triggered the replacement.
2879        context..........the context (machine state) to which the
2880                             replacement should be applied.
2881
2882    OUT:
2883        context..........the context after replacement finished.
2884
2885    RETURN VALUE:
2886        true.............replacement done, everything went ok
2887        false............no replacement done, context unchanged
2888
2889 *******************************************************************************/
2890
2891 bool replace_me_wrapper(u1 *pc, void *context)
2892 {
2893         codeinfo         *code;
2894         rplpoint         *rp;
2895         executionstate_t  es;
2896
2897         /* search the codeinfo for the given PC */
2898
2899         code = code_find_codeinfo_for_pc(pc);
2900         assert(code);
2901
2902         /* search for a replacement point at the given PC */
2903
2904         rp = replace_find_replacement_point_for_pc(code, pc);
2905
2906         /* check if the replacement point belongs to given PC and is active */
2907
2908         if ((rp != NULL) && (rp->pc == pc) && (rp->flags & RPLPOINT_FLAG_ACTIVE)) {
2909
2910                 /* set codeinfo pointer in execution state */
2911
2912                 es.code = code;
2913
2914                 /* read execution state from current context */
2915
2916                 md_replace_executionstate_read(&es, context);
2917
2918                 DOLOG( printf("REPLACEMENT READ: ");
2919                            replace_executionstate_println(&es); );
2920
2921                 /* do the actual replacement */
2922
2923                 replace_me(rp, &es);
2924
2925                 /* write execution state to current context */
2926
2927                 md_replace_executionstate_write(&es, context);
2928
2929                 DOLOG( printf("REPLACEMENT WRITE: ");
2930                            replace_executionstate_println(&es); );
2931
2932                 /* new code is entered after returning */
2933
2934                 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
2935                 return true;
2936         }
2937         else
2938                 return false;
2939 }
2940
2941
2942 /******************************************************************************/
2943 /* NOTE: Stuff specific to the exact GC is below.                             */
2944 /******************************************************************************/
2945
2946 #if defined(ENABLE_GC_CACAO)
2947 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
2948 {
2949         stackframeinfo   *sfi;
2950         executionstate_t *es;
2951         sourcestate_t    *ss;
2952
2953         /* get the stackframeinfo of this thread */
2954         assert(thread == THREADOBJECT);
2955         sfi = STACKFRAMEINFO;
2956
2957         /* create the execution state */
2958         es = DNEW(executionstate_t);
2959         es->pc = pc;
2960         es->sp = sp;
2961         es->pv = 0;      /* since we are in a native, PV is invalid! */
2962         es->code = NULL; /* since we are in a native, we do not have a codeinfo */
2963
2964         /* we assume we are in a native (no replacement point)! */
2965         ss = replace_recover_source_state(NULL, sfi, es);
2966
2967         /* map the sourcestate using the identity mapping */
2968         replace_map_source_state_identity(ss);
2969
2970         /* remember executionstate and sourcestate for this thread */
2971         GC_EXECUTIONSTATE = es;
2972         GC_SOURCESTATE    = ss;
2973 }
2974 #endif
2975
2976 #if defined(ENABLE_GC_CACAO)
2977 void replace_gc_into_native(threadobject *thread)
2978 {
2979         executionstate_t *es;
2980         sourcestate_t    *ss;
2981
2982         /* get the executionstate and sourcestate for the given thread */
2983         es = GC_EXECUTIONSTATE;
2984         ss = GC_SOURCESTATE;
2985
2986         /* rebuild the stack of the given thread */
2987         replace_build_execution_state(ss, es);
2988 }
2989 #endif
2990
2991
2992 /******************************************************************************/
2993 /* NOTE: No important code below.                                             */
2994 /******************************************************************************/
2995
2996
2997 /* statistics *****************************************************************/
2998
2999 #if defined(REPLACE_STATISTICS)
3000 static void print_freq(FILE *file,int *array,int limit)
3001 {
3002         int i;
3003         int sum = 0;
3004         int cum = 0;
3005         for (i=0; i<limit; ++i)
3006                 sum += array[i];
3007         sum += array[limit];
3008         for (i=0; i<limit; ++i) {
3009                 cum += array[i];
3010                 fprintf(file,"      %3d: %8d (cum %3d%%)\n",
3011                                 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3012         }
3013         fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
3014 }
3015 #endif /* defined(REPLACE_STATISTICS) */
3016
3017
3018 #if defined(REPLACE_STATISTICS)
3019
3020 #define REPLACE_PRINT_DIST(name, array)                              \
3021     printf("    " name " distribution:\n");                          \
3022     print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3023
3024 void replace_print_statistics(void)
3025 {
3026         printf("replacement statistics:\n");
3027         printf("    # of replacements:   %d\n", stat_replacements);
3028         printf("    # of frames:         %d\n", stat_frames);
3029         printf("    # of recompilations: %d\n", stat_recompile);
3030         printf("    patched static calls:%d\n", stat_staticpatch);
3031         printf("    unrolled inlines:    %d\n", stat_unroll_inline);
3032         printf("    unrolled calls:      %d\n", stat_unroll_call);
3033         REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3034         REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3035         REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3036         REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3037         REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3038         REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3039         REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3040         REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3041         REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3042         REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3043         printf("\n");
3044         printf("    # of methods:            %d\n", stat_methods);
3045         printf("    # of replacement points: %d\n", stat_rploints);
3046         printf("    # of regallocs:          %d\n", stat_regallocs);
3047         printf("        per rplpoint:        %f\n", (double)stat_regallocs / stat_rploints);
3048         printf("        per method:          %f\n", (double)stat_regallocs / stat_methods);
3049         REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3050         printf("\n");
3051
3052 }
3053 #endif /* defined(REPLACE_STATISTICS) */
3054
3055
3056 #if defined(REPLACE_STATISTICS)
3057 static void replace_statistics_source_frame(sourceframe_t *frame)
3058 {
3059         int adr = 0;
3060         int ret = 0;
3061         int prim = 0;
3062         int vd = 0;
3063         int n = 0;
3064         int i;
3065
3066         for (i=0; i<frame->javalocalcount; ++i) {
3067                 switch (frame->javalocaltype[i]) {
3068                         case TYPE_ADR: adr++; break;
3069                         case TYPE_RET: ret++; break;
3070                         case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3071                         case TYPE_VOID: vd++; break;
3072                         default: assert(0);
3073                 }
3074                 n++;
3075         }
3076         REPLACE_COUNT_DIST(stat_dist_locals, n);
3077         REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3078         REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3079         REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3080         REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3081         adr = ret = prim = n = 0;
3082         for (i=0; i<frame->javastackdepth; ++i) {
3083                 switch (frame->javastacktype[i]) {
3084                         case TYPE_ADR: adr++; break;
3085                         case TYPE_RET: ret++; break;
3086                         case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3087                 }
3088                 n++;
3089         }
3090         REPLACE_COUNT_DIST(stat_dist_stack, n);
3091         REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3092         REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3093         REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3094 }
3095 #endif /* defined(REPLACE_STATISTICS) */
3096
3097
3098 /* debugging helpers **********************************************************/
3099
3100 /* replace_replacement_point_println *******************************************
3101  
3102    Print replacement point info.
3103   
3104    IN:
3105        rp...............the replacement point to print
3106   
3107 *******************************************************************************/
3108
3109 #if !defined(NDEBUG)
3110
3111 #define TYPECHAR(t)  (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3112
3113 static char *replace_type_str[] = {
3114         "STD",
3115         "EXH",
3116         "SBR",
3117         "CALL",
3118         "INLINE",
3119         "RETURN",
3120         "BODY"
3121 };
3122
3123 void replace_replacement_point_println(rplpoint *rp, int depth)
3124 {
3125         int j;
3126         int index;
3127
3128         if (!rp) {
3129                 printf("(rplpoint *)NULL\n");
3130                 return;
3131         }
3132
3133         for (j=0; j<depth; ++j)
3134                 putchar('\t');
3135
3136         printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3137                         rp->id, (void*)rp,rp->pc,rp->callsize,
3138                         replace_type_str[rp->type]);
3139         if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3140                 printf(" NOTRAP");
3141         if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3142                 printf(" COUNTDOWN");
3143         if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3144                 printf(" ACTIVE");
3145         printf(" parent:%p\n", (void*)rp->parent);
3146         for (j=0; j<depth; ++j)
3147                 putchar('\t');
3148         printf("ra:%d = [",     rp->regalloccount);
3149
3150         for (j=0; j<rp->regalloccount; ++j) {
3151                 if (j)
3152                         putchar(' ');
3153                 index = rp->regalloc[j].index;
3154                 switch (index) {
3155                         case RPLALLOC_STACK: printf("S"); break;
3156                         case RPLALLOC_PARAM: printf("P"); break;
3157                         case RPLALLOC_SYNC : printf("Y"); break;
3158                         default: printf("%d", index);
3159                 }
3160                 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3161                 if (rp->regalloc[j].type == TYPE_RET) {
3162                         printf("ret(L%03d)", rp->regalloc[j].regoff);
3163                 }
3164                 else {
3165                         show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3166                 }
3167         }
3168
3169         printf("]\n");
3170         for (j=0; j<depth; ++j)
3171                 putchar('\t');
3172         printf("method: ");
3173         method_print(rp->method);
3174
3175         printf("\n");
3176 }
3177 #endif /* !defined(NDEBUG) */
3178
3179
3180 /* replace_show_replacement_points *********************************************
3181  
3182    Print replacement point info.
3183   
3184    IN:
3185        code.............codeinfo whose replacement points should be printed.
3186   
3187 *******************************************************************************/
3188
3189 #if !defined(NDEBUG)
3190 void replace_show_replacement_points(codeinfo *code)
3191 {
3192         int i;
3193         int depth;
3194         rplpoint *rp;
3195         rplpoint *parent;
3196
3197         if (!code) {
3198                 printf("(codeinfo *)NULL\n");
3199                 return;
3200         }
3201
3202         printf("\treplacement points: %d\n",code->rplpointcount);
3203
3204         printf("\ttotal allocations : %d\n",code->regalloccount);
3205         printf("\tsaved int regs    : %d\n",code->savedintcount);
3206         printf("\tsaved flt regs    : %d\n",code->savedfltcount);
3207 #if defined(HAS_ADDRESS_REGISTER_FILE)
3208         printf("\tsaved adr regs    : %d\n",code->savedadrcount);
3209 #endif
3210         printf("\tmemuse            : %d\n",code->memuse);
3211
3212         printf("\n");
3213
3214         for (i=0; i<code->rplpointcount; ++i) {
3215                 rp = code->rplpoints + i;
3216
3217                 depth = 1;
3218                 parent = rp->parent;
3219                 while (parent) {
3220                         depth++;
3221                         parent = parent->parent;
3222                 }
3223                 replace_replacement_point_println(rp, depth);
3224         }
3225 }
3226 #endif
3227
3228
3229 /* replace_executionstate_println **********************************************
3230  
3231    Print execution state
3232   
3233    IN:
3234        es...............the execution state to print
3235   
3236 *******************************************************************************/
3237
3238 #if !defined(NDEBUG)
3239 void replace_executionstate_println(executionstate_t *es)
3240 {
3241         int i;
3242         int slots;
3243         stackslot_t *sp;
3244         int extraslots;
3245
3246         if (!es) {
3247                 printf("(executionstate_t *)NULL\n");
3248                 return;
3249         }
3250
3251         printf("executionstate_t:\n");
3252         printf("\tpc = %p",(void*)es->pc);
3253         printf("  sp = %p",(void*)es->sp);
3254         printf("  pv = %p\n",(void*)es->pv);
3255 #if defined(ENABLE_DISASSEMBLER)
3256         for (i=0; i<INT_REG_CNT; ++i) {
3257                 if (i%4 == 0)
3258                         printf("\t");
3259                 else
3260                         printf(" ");
3261 #if SIZEOF_VOID_P == 8
3262                 printf("%-3s = %016llx",abi_registers_integer_name[i],(unsigned long long)es->intregs[i]);
3263 #else
3264                 printf("%-3s = %08lx",abi_registers_integer_name[i],(unsigned long)es->intregs[i]);
3265 #endif
3266                 if (i%4 == 3)
3267                         printf("\n");
3268         }
3269         for (i=0; i<FLT_REG_CNT; ++i) {
3270                 if (i%4 == 0)
3271                         printf("\t");
3272                 else
3273                         printf(" ");
3274                 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
3275                 if (i%4 == 3)
3276                         printf("\n");
3277         }
3278 # if defined(HAS_ADDRESS_REGISTER_FILE)
3279         for (i=0; i<ADR_REG_CNT; ++i) {
3280                 if (i%4 == 0)
3281                         printf("\t");
3282                 else
3283                         printf(" ");
3284                 printf("A%02d = %016llx",i,(unsigned long long)es->adrregs[i]);
3285                 if (i%4 == 3)
3286                         printf("\n");
3287         }
3288 # endif
3289 #endif
3290
3291         sp = (stackslot_t *) es->sp;
3292
3293         extraslots = 2;
3294
3295         if (es->code) {
3296                 methoddesc *md = es->code->m->parseddesc;
3297                 slots = es->code->stackframesize;
3298                 extraslots = 1 + md->memuse;
3299         }
3300         else
3301                 slots = 0;
3302
3303
3304         if (slots) {
3305                 printf("\tstack slots(+%d) at sp:", extraslots);
3306                 for (i=0; i<slots+extraslots; ++i) {
3307                         if (i%4 == 0)
3308                                 printf("\n\t\t");
3309                         printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
3310 #ifdef HAS_4BYTE_STACKSLOT
3311                         printf("%08lx",(unsigned long)*sp++);
3312 #else
3313                         printf("%016llx",(unsigned long long)*sp++);
3314 #endif
3315                         printf("%c", (i >= slots) ? ')' : ' ');
3316                 }
3317                 printf("\n");
3318         }
3319
3320         printf("\tcode: %p", (void*)es->code);
3321         if (es->code != NULL) {
3322                 printf(" stackframesize=%d ", es->code->stackframesize);
3323                 method_print(es->code->m);
3324         }
3325         printf("\n");
3326
3327         printf("\n");
3328 }
3329 #endif
3330
3331 #if !defined(NDEBUG)
3332 static void java_value_print(s4 type, replace_val_t value)
3333 {
3334         java_object_t *obj;
3335         utf           *u;
3336
3337         printf("%016llx",(unsigned long long) value.l);
3338
3339         if (type < 0 || type > TYPE_RET)
3340                 printf(" <INVALID TYPE:%d>", type);
3341         else
3342                 printf(" %s", show_jit_type_names[type]);
3343
3344         if (type == TYPE_ADR && value.a != NULL) {
3345                 obj = value.a;
3346                 putchar(' ');
3347                 utf_display_printable_ascii_classname(obj->vftbl->class->name);
3348
3349                 if (obj->vftbl->class == class_java_lang_String) {
3350                         printf(" \"");
3351                         u = javastring_toutf(obj, false);
3352                         utf_display_printable_ascii(u);
3353                         printf("\"");
3354                 }
3355         }
3356         else if (type == TYPE_INT) {
3357                 printf(" %ld", (long) value.i);
3358         }
3359         else if (type == TYPE_LNG) {
3360                 printf(" %lld", (long long) value.l);
3361         }
3362         else if (type == TYPE_FLT) {
3363                 printf(" %f", value.f);
3364         }
3365         else if (type == TYPE_DBL) {
3366                 printf(" %f", value.d);
3367         }
3368 }
3369 #endif /* !defined(NDEBUG) */
3370
3371
3372 #if !defined(NDEBUG)
3373 void replace_source_frame_println(sourceframe_t *frame)
3374 {
3375         s4 i,j;
3376         s4 t;
3377
3378         if (REPLACE_IS_NATIVE_FRAME(frame)) {
3379                 printf("\tNATIVE\n");
3380                 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3381                 printf("\tnativepc: %p\n", frame->nativepc);
3382                 printf("\tframesize: %d\n", frame->nativeframesize);
3383
3384                 j = 0;
3385                 for (i=0; i<INT_REG_CNT; ++i) {
3386                         if (nregdescint[i] == REG_SAV)
3387                                 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3388                 }
3389
3390                 j = 0;
3391                 for (i=0; i<FLT_REG_CNT; ++i) {
3392                         if (nregdescfloat[i] == REG_SAV)
3393                                 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3394                 }
3395
3396                 printf("\n");
3397                 return;
3398         }
3399
3400         printf("\t");
3401         method_println(frame->method);
3402         printf("\tid: %d\n", frame->id);
3403         printf("\ttype: %s\n", replace_type_str[frame->type]);
3404         printf("\n");
3405
3406         if (frame->instance.a) {
3407                 printf("\tinstance: ");
3408                 java_value_print(TYPE_ADR, frame->instance);
3409                 printf("\n");
3410         }
3411
3412         if (frame->javalocalcount) {
3413                 printf("\tlocals (%d):\n",frame->javalocalcount);
3414                 for (i=0; i<frame->javalocalcount; ++i) {
3415                         t = frame->javalocaltype[i];
3416                         if (t == TYPE_VOID) {
3417                                 printf("\tlocal[ %2d] = void\n",i);
3418                         }
3419                         else {
3420                                 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3421                                 java_value_print(t, frame->javalocals[i]);
3422                                 printf("\n");
3423                         }
3424                 }
3425                 printf("\n");
3426         }
3427
3428         if (frame->javastackdepth) {
3429                 printf("\tstack (depth %d):\n",frame->javastackdepth);
3430                 for (i=0; i<frame->javastackdepth; ++i) {
3431                         t = frame->javastacktype[i];
3432                         if (t == TYPE_VOID) {
3433                                 printf("\tstack[%2d] = void", i);
3434                         }
3435                         else {
3436                                 printf("\tstack[%2d] = ",i);
3437                                 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3438                                 printf("\n");
3439                         }
3440                 }
3441                 printf("\n");
3442         }
3443
3444         if (frame->syncslotcount) {
3445                 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3446                 for (i=0; i<frame->syncslotcount; ++i) {
3447                         printf("\tslot[%2d] = ",i);
3448 #ifdef HAS_4BYTE_STACKSLOT
3449                         printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3450 #else
3451                         printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3452 #endif
3453                 }
3454                 printf("\n");
3455         }
3456
3457         if (frame->fromcode) {
3458                 printf("\tfrom %p ", (void*)frame->fromcode);
3459                 method_println(frame->fromcode->m);
3460         }
3461         if (frame->tocode) {
3462                 printf("\tto %p ", (void*)frame->tocode);
3463                 method_println(frame->tocode->m);
3464         }
3465
3466         if (frame->fromrp) {
3467                 printf("\tfrom replacement point:\n");
3468                 replace_replacement_point_println(frame->fromrp, 2);
3469         }
3470         if (frame->torp) {
3471                 printf("\tto replacement point:\n");
3472                 replace_replacement_point_println(frame->torp, 2);
3473         }
3474
3475         printf("\n");
3476 }
3477 #endif /* !defined(NDEBUG) */
3478
3479
3480 /* replace_sourcestate_println *************************************************
3481  
3482    Print source state
3483   
3484    IN:
3485        ss...............the source state to print
3486   
3487 *******************************************************************************/
3488
3489 #if !defined(NDEBUG)
3490 void replace_sourcestate_println(sourcestate_t *ss)
3491 {
3492         int i;
3493         sourceframe_t *frame;
3494
3495         if (!ss) {
3496                 printf("(sourcestate_t *)NULL\n");
3497                 return;
3498         }
3499
3500         printf("sourcestate_t:\n");
3501
3502         for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3503                 printf("    frame %d:\n", i);
3504                 replace_source_frame_println(frame);
3505         }
3506 }
3507 #endif
3508
3509
3510 /* replace_sourcestate_println_short *******************************************
3511
3512    Print a compact representation of the given source state.
3513
3514    IN:
3515        ss...............the source state to print
3516
3517 *******************************************************************************/
3518
3519 #if !defined(NDEBUG)
3520 void replace_sourcestate_println_short(sourcestate_t *ss)
3521 {
3522         sourceframe_t *frame;
3523
3524         for (frame = ss->frames; frame != NULL; frame = frame->down) {
3525                 printf("\t");
3526
3527                 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3528                         printf("NATIVE (pc %p size %d) ",
3529                                         (void*)frame->nativepc, frame->nativeframesize);
3530                         replace_stackframeinfo_println(frame->sfi);
3531                         continue;
3532                 }
3533
3534                 if (frame->torp) {
3535                         printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3536                 }
3537
3538                 printf("%s", replace_type_str[frame->fromrp->type]);
3539
3540                 if (frame->torp && frame->torp->type != frame->fromrp->type)
3541                         printf("->%s", replace_type_str[frame->torp->type]);
3542
3543                 if (frame->tocode != frame->fromcode)
3544                         printf(" (%p->%p/%d) ",
3545                                    (void*) frame->fromcode, (void*) frame->tocode,
3546                                    frame->fromrp->id);
3547                 else
3548                         printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3549
3550                 method_println(frame->method);
3551         }
3552 }
3553 #endif
3554
3555 #if !defined(NDEBUG)
3556 static void replace_stackframeinfo_println(stackframeinfo *sfi)
3557 {
3558         printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3559                         (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3560                         (void*)sfi->ra, (void*)sfi->xpc);
3561
3562         if (sfi->method)
3563                 method_println(sfi->method);
3564         else
3565                 printf("(nil)\n");
3566 }
3567 #endif
3568
3569 /*
3570  * These are local overrides for various environment variables in Emacs.
3571  * Please do not remove this and leave it at the end of the file, where
3572  * Emacs will automagically detect them.
3573  * ---------------------------------------------------------------------
3574  * Local variables:
3575  * mode: c
3576  * indent-tabs-mode: t
3577  * c-basic-offset: 4
3578  * tab-width: 4
3579  * End:
3580  * vim:noexpandtab:sw=4:ts=4:
3581  */