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