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