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