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