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