52326d450ccdc8d80fe6f279fe528088d498f694
[cacao.git] / src / vm / jit / replace.c
1 /* src/vm/jit/replace.c - on-stack replacement of methods
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25 #include "config.h"
26 #include "vm/types.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31
32 #include "arch.h"
33 #include "md.h"
34
35 #if defined(ENABLE_GC_CACAO)
36 # include "mm/cacao-gc/gc.h"
37 #endif
38
39 #include "mm/memory.h"
40
41 #include "threads/thread.hpp"
42
43 #include "toolbox/logging.h"
44
45 #include "vm/string.hpp"
46
47 #include "vm/jit/abi.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/executionstate.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/methodheader.h"
53 #include "vm/jit/replace.h"
54 #include "vm/jit/show.h"
55 #include "vm/jit/stack.h"
56
57 #include "vmcore/classcache.h"
58 #include "vmcore/globals.hpp"
59 #include "vmcore/options.h"
60
61 #if defined(ENABLE_RT_TIMING)
62 # include "vmcore/rt-timing.h"
63 #endif
64
65 #define REPLACE_PATCH_DYNAMIC_CALL
66 /*#define REPLACE_PATCH_ALL*/
67
68 #if defined(ENABLE_VMLOG)
69 #include <vmlog_cacao.h>
70 #endif
71
72 /*** architecture-dependent configuration *************************************/
73
74 /* first unset the macros (default) */
75 #undef REPLACE_RA_BETWEEN_FRAMES
76 #undef REPLACE_RA_TOP_OF_FRAME
77 #undef REPLACE_RA_LINKAGE_AREA
78 #undef REPLACE_LEAFMETHODS_RA_REGISTER
79
80 /* i386, x86_64 and m68k */
81 #if defined(__I386__) || defined(__X86_64__) || defined(__M68K__)
82 #define REPLACE_RA_BETWEEN_FRAMES
83 /* alpha */
84 #elif defined(__ALPHA__)
85 #define REPLACE_RA_TOP_OF_FRAME
86 #define REPLACE_LEAFMETHODS_RA_REGISTER
87 /* powerpc */
88 #elif defined(__POWERPC__)
89 #define REPLACE_RA_LINKAGE_AREA
90 #define REPLACE_LEAFMETHODS_RA_REGISTER
91 /* s390 */
92 #elif defined(__S390__)
93 #define REPLACE_RA_TOP_OF_FRAME
94 #endif
95
96
97 /*** configuration of native stack slot size **********************************/
98
99 /* XXX this should be in md-abi.h files, probably */
100
101 #if defined(HAS_4BYTE_STACKSLOT)
102 #define SIZE_OF_STACKSLOT      4
103 #define STACK_SLOTS_PER_FLOAT  2
104 typedef u4 stackslot_t;
105 #else
106 #define SIZE_OF_STACKSLOT      8
107 #define STACK_SLOTS_PER_FLOAT  1
108 typedef u8 stackslot_t;
109 #endif
110
111
112 /*** debugging ****************************************************************/
113
114 #if !defined(NDEBUG)
115 static void java_value_print(s4 type, replace_val_t value);
116 static void replace_stackframeinfo_println(stackframeinfo_t *sfi);
117 #endif
118
119 #if !defined(NDEBUG)
120 #define DOLOG(code)        do{ if (opt_TraceReplacement > 1) { code; } } while(0)
121 #define DOLOG_SHORT(code)  do{ if (opt_TraceReplacement > 0) { code; } } while(0)
122 #else
123 #define DOLOG(code)
124 #define DOLOG_SHORT(code)
125 #endif
126
127
128 /*** statistics ***************************************************************/
129
130 #define REPLACE_STATISTICS
131
132 #if defined(REPLACE_STATISTICS)
133
134 static int stat_replacements = 0;
135 static int stat_frames = 0;
136 static int stat_recompile = 0;
137 static int stat_staticpatch = 0;
138 static int stat_unroll_inline = 0;
139 static int stat_unroll_call = 0;
140 static int stat_dist_frames[20] = { 0 };
141 static int stat_dist_locals[20] = { 0 };
142 static int stat_dist_locals_adr[10] = { 0 };
143 static int stat_dist_locals_prim[10] = { 0 };
144 static int stat_dist_locals_ret[10] = { 0 };
145 static int stat_dist_locals_void[10] = { 0 };
146 static int stat_dist_stack[10] = { 0 };
147 static int stat_dist_stack_adr[10] = { 0 };
148 static int stat_dist_stack_prim[10] = { 0 };
149 static int stat_dist_stack_ret[10] = { 0 };
150 static int stat_methods = 0;
151 static int stat_rploints = 0;
152 static int stat_regallocs = 0;
153 static int stat_dist_method_rplpoints[20] = { 0 };
154
155 #define REPLACE_COUNT(cnt)  (cnt)++
156 #define REPLACE_COUNT_IF(cnt, cond)  do{ if(cond) (cnt)++; } while(0)
157 #define REPLACE_COUNT_INC(cnt, inc)  ((cnt) += (inc))
158
159 #define REPLACE_COUNT_DIST(array, val)                               \
160     do {                                                             \
161         int limit = (sizeof(array) / sizeof(int)) - 1;               \
162         if ((val) < (limit)) (array)[val]++;                         \
163         else (array)[limit]++;                                       \
164     } while (0)
165
166 static void replace_statistics_source_frame(sourceframe_t *frame);
167
168 #else
169
170 #define REPLACE_COUNT(cnt)
171 #define REPLACE_COUNT_IF(cnt, cond)
172 #define REPLACE_COUNT_INC(cnt, inc)
173 #define REPLACE_COUNT_DIST(array, val)
174
175 #endif /* defined(REPLACE_STATISTICS) */
176
177
178 /*** constants used internally ************************************************/
179
180 #define TOP_IS_NORMAL    0
181 #define TOP_IS_ON_STACK  1
182 #define TOP_IS_IN_ITMP1  2
183 #define TOP_IS_VOID      3
184
185
186 /******************************************************************************/
187 /* PART I: Creating / freeing replacement points                              */
188 /******************************************************************************/
189
190
191 /* replace_create_replacement_point ********************************************
192  
193    Create a replacement point.
194   
195    IN:
196        jd...............current jitdata
197            iinfo............inlining info for the current position
198            rp...............pre-allocated (uninitialized) rplpoint
199            type.............RPLPOINT_TYPE constant
200            iptr.............current instruction
201            *pra.............current rplalloc pointer
202            javalocals.......the javalocals at the current point
203            stackvars........the stack variables at the current point
204            stackdepth.......the stack depth at the current point
205            paramcount.......number of parameters at the start of stackvars
206   
207    OUT:
208        *rpa.............points to the next free rplalloc
209   
210 *******************************************************************************/
211
212 static void replace_create_replacement_point(jitdata *jd,
213                                                                                          insinfo_inline *iinfo,
214                                                                                          rplpoint *rp,
215                                                                                          s4 type,
216                                                                                          instruction *iptr,
217                                                                                          rplalloc **pra,
218                                                                                          s4 *javalocals,
219                                                                                          s4 *stackvars,
220                                                                                          s4 stackdepth,
221                                                                                          s4 paramcount)
222 {
223         rplalloc *ra;
224         s4        i;
225         varinfo  *v;
226         s4        index;
227
228         ra = *pra;
229
230         REPLACE_COUNT(stat_rploints);
231
232         rp->method = (iinfo) ? iinfo->method : jd->m;
233         rp->pc = NULL;        /* set by codegen */
234         rp->callsize = 0;     /* set by codegen */
235         rp->regalloc = ra;
236         rp->flags = 0;
237         rp->type = type;
238         rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
239
240         /* XXX unify these two fields */
241         rp->parent = (iinfo) ? iinfo->rp : NULL;
242
243         /* store local allocation info of javalocals */
244
245         if (javalocals) {
246                 for (i = 0; i < rp->method->maxlocals; ++i) {
247                         index = javalocals[i];
248                         if (index == UNUSED)
249                                 continue;
250
251                         ra->index = i;
252                         if (index >= 0) {
253                                 v = VAR(index);
254                                 ra->flags = v->flags & (INMEMORY);
255                                 ra->regoff = v->vv.regoff;
256                                 ra->type = v->type;
257                         }
258                         else {
259                                 ra->regoff = RETADDR_FROM_JAVALOCAL(index);
260                                 ra->type = TYPE_RET;
261                                 ra->flags = 0;
262                         }
263                         ra++;
264                 }
265         }
266
267         /* store allocation info of java stack vars */
268
269         for (i = 0; i < stackdepth; ++i) {
270                 v = VAR(stackvars[i]);
271                 ra->flags = v->flags & (INMEMORY);
272                 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
273                 ra->type  = v->type;
274                 /* XXX how to handle locals on the stack containing returnAddresses? */
275                 if (v->type == TYPE_RET) {
276                         assert(stackvars[i] >= jd->localcount);
277                         ra->regoff = v->vv.retaddr->nr;
278                 }
279                 else
280                         ra->regoff = v->vv.regoff;
281                 ra++;
282         }
283
284         /* total number of allocations */
285
286         rp->regalloccount = ra - rp->regalloc;
287
288         *pra = ra;
289 }
290
291
292 /* replace_create_inline_start_replacement_point *******************************
293
294    Create an INLINE_START replacement point.
295
296    IN:
297        jd...............current jitdata
298            rp...............pre-allocated (uninitialized) rplpoint
299            iptr.............current instruction
300            *pra.............current rplalloc pointer
301            javalocals.......the javalocals at the current point
302
303    OUT:
304        *rpa.............points to the next free rplalloc
305
306    RETURN VALUE:
307        the insinfo_inline * for the following inlined body
308
309 *******************************************************************************/
310
311 static insinfo_inline * replace_create_inline_start_replacement_point(
312                                                                                          jitdata *jd,
313                                                                                          rplpoint *rp,
314                                                                                          instruction *iptr,
315                                                                                          rplalloc **pra,
316                                                                                          s4 *javalocals)
317 {
318         insinfo_inline *calleeinfo;
319         rplalloc       *ra;
320
321         calleeinfo = iptr->sx.s23.s3.inlineinfo;
322
323         calleeinfo->rp = rp;
324
325         replace_create_replacement_point(jd, calleeinfo->parent, rp,
326                         RPLPOINT_TYPE_INLINE, iptr, pra,
327                         javalocals,
328                         calleeinfo->stackvars, calleeinfo->stackvarscount,
329                         calleeinfo->paramcount);
330
331         if (calleeinfo->synclocal != UNUSED) {
332                 ra = (*pra)++;
333                 ra->index  = RPLALLOC_SYNC;
334                 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
335                 ra->flags  = jd->var[calleeinfo->synclocal].flags & INMEMORY;
336                 ra->type   = TYPE_ADR;
337
338                 rp->regalloccount++;
339         }
340
341         return calleeinfo;
342 }
343
344
345 /* replace_create_replacement_points *******************************************
346  
347    Create the replacement points for the given code.
348   
349    IN:
350        jd...............current jitdata, must not have any replacement points
351   
352    OUT:
353        code->rplpoints.......set to the list of replacement points
354            code->rplpointcount...number of replacement points
355            code->regalloc........list of allocation info
356            code->regalloccount...total length of allocation info list
357            code->globalcount.....number of global allocations at the
358                                  start of code->regalloc
359   
360    RETURN VALUE:
361        true.............everything ok 
362        false............an exception has been thrown
363    
364 *******************************************************************************/
365
366 #define CLEAR_javalocals(array, method)                              \
367     do {                                                             \
368         for (i=0; i<(method)->maxlocals; ++i)                        \
369             (array)[i] = UNUSED;                                     \
370     } while (0)
371
372 #define COPY_OR_CLEAR_javalocals(dest, array, method)                \
373     do {                                                             \
374         if ((array) != NULL)                                         \
375             MCOPY((dest), (array), s4, (method)->maxlocals);         \
376         else                                                         \
377             CLEAR_javalocals((dest), (method));                      \
378     } while (0)
379
380 #define COUNT_javalocals(array, method, counter)                     \
381     do {                                                             \
382         for (i=0; i<(method)->maxlocals; ++i)                        \
383             if ((array)[i] != UNUSED)                                \
384                                 (counter)++;                                         \
385     } while (0)
386
387 bool replace_create_replacement_points(jitdata *jd)
388 {
389         codeinfo        *code;
390         registerdata    *rd;
391         basicblock      *bptr;
392         int              count;
393         methodinfo      *m;
394         rplpoint        *rplpoints;
395         rplpoint        *rp;
396         int              alloccount;
397         rplalloc        *regalloc;
398         rplalloc        *ra;
399         int              i;
400         instruction     *iptr;
401         instruction     *iend;
402         s4              *javalocals;
403         s4              *jl;
404         methoddesc      *md;
405         insinfo_inline  *iinfo;
406         s4               startcount;
407         s4               firstcount;
408 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
409         bool             needentry;
410 #endif
411
412         REPLACE_COUNT(stat_methods);
413
414         /* get required compiler data */
415
416         code = jd->code;
417         rd   = jd->rd;
418
419         /* assert that we wont overwrite already allocated data */
420
421         assert(code);
422         assert(code->m);
423         assert(code->rplpoints == NULL);
424         assert(code->rplpointcount == 0);
425         assert(code->regalloc == NULL);
426         assert(code->regalloccount == 0);
427         assert(code->globalcount == 0);
428
429         m = code->m;
430
431         /* in instance methods, we may need a rplpoint at the method entry */
432
433 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
434         if (!(m->flags & ACC_STATIC)) {
435                 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
436                 needentry = true;
437         }
438         else {
439                 needentry = false;
440         }
441 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
442
443         /* iterate over the basic block list to find replacement points */
444
445         count = 0;
446         alloccount = 0;
447
448         javalocals = DMNEW(s4, jd->maxlocals);
449
450         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
451
452                 /* skip dead code */
453
454                 if (bptr->flags < BBFINISHED)
455                         continue;
456
457                 /* get info about this block */
458
459                 m = bptr->method;
460                 iinfo = bptr->inlineinfo;
461
462                 /* initialize javalocals at the start of this block */
463
464                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
465
466                 /* iterate over the instructions */
467
468                 iptr = bptr->iinstr;
469                 iend = iptr + bptr->icount;
470                 startcount = count;
471                 firstcount = count;
472
473                 for (; iptr != iend; ++iptr) {
474                         switch (iptr->opc) {
475 #if defined(ENABLE_GC_CACAO)
476                                 case ICMD_BUILTIN:
477                                         md = iptr->sx.s23.s3.bte->md;
478                                         count++;
479                                         COUNT_javalocals(javalocals, m, alloccount);
480                                         alloccount += iptr->s1.argcount;
481                                         if (iinfo)
482                                                 alloccount -= iinfo->throughcount;
483                                         break;
484 #endif
485
486                                 case ICMD_INVOKESTATIC:
487                                 case ICMD_INVOKESPECIAL:
488                                 case ICMD_INVOKEVIRTUAL:
489                                 case ICMD_INVOKEINTERFACE:
490                                         INSTRUCTION_GET_METHODDESC(iptr, md);
491                                         count++;
492                                         COUNT_javalocals(javalocals, m, alloccount);
493                                         alloccount += iptr->s1.argcount;
494                                         if (iinfo)
495                                                 alloccount -= iinfo->throughcount;
496                                         break;
497
498                                 case ICMD_ISTORE:
499                                 case ICMD_LSTORE:
500                                 case ICMD_FSTORE:
501                                 case ICMD_DSTORE:
502                                 case ICMD_ASTORE:
503                                         stack_javalocals_store(iptr, javalocals);
504                                         break;
505
506                                 case ICMD_IRETURN:
507                                 case ICMD_LRETURN:
508                                 case ICMD_FRETURN:
509                                 case ICMD_DRETURN:
510                                 case ICMD_ARETURN:
511                                         alloccount += 1;
512                                         /* FALLTHROUGH! */
513                                 case ICMD_RETURN:
514                                         count++;
515                                         break;
516
517                                 case ICMD_INLINE_START:
518                                         iinfo = iptr->sx.s23.s3.inlineinfo;
519
520                                         count++;
521                                         COUNT_javalocals(javalocals, m, alloccount);
522                                         alloccount += iinfo->stackvarscount;
523                                         if (iinfo->synclocal != UNUSED)
524                                                 alloccount++;
525
526                                         m = iinfo->method;
527                                         /* javalocals may be set at next block start, or now */
528                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
529                                         break;
530
531                                 case ICMD_INLINE_BODY:
532                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
533
534                                         jl = iinfo->javalocals_start;
535                                         if (jl == NULL) {
536                                                 /* get the javalocals from the following block start */
537                                                 assert(bptr->next);
538                                                 jl = bptr->next->javalocals;
539                                         }
540                                         count++;
541                                         COUNT_javalocals(jl, m, alloccount);
542                                         break;
543
544                                 case ICMD_INLINE_END:
545                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
546                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
547                                         iinfo = iptr->sx.s23.s3.inlineinfo;
548                                         m = iinfo->outer;
549                                         if (iinfo->javalocals_end)
550                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
551                                         iinfo = iinfo->parent;
552                                         break;
553                         }
554
555                         if (iptr == bptr->iinstr)
556                                 firstcount = count;
557                 } /* end instruction loop */
558
559                 /* create replacement points at targets of backward branches */
560                 /* We only need the replacement point there, if there is no  */
561                 /* replacement point inside the block.                       */
562
563                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
564 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
565                         int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
566 #else
567                         int test = count;
568 #endif
569                         if (test > startcount) {
570                                 /* we don't need an extra rplpoint */
571                                 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
572                         }
573                         else {
574                                 count++;
575                                 alloccount += bptr->indepth;
576                                 if (bptr->inlineinfo)
577                                         alloccount -= bptr->inlineinfo->throughcount;
578
579                                 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
580                         }
581                 }
582
583         } /* end basicblock loop */
584
585         /* if no points were found, there's nothing to do */
586
587         if (!count)
588                 return true;
589
590         /* allocate replacement point array and allocation array */
591
592         rplpoints = MNEW(rplpoint, count);
593         regalloc = MNEW(rplalloc, alloccount);
594         ra = regalloc;
595
596         /* initialize replacement point structs */
597
598         rp = rplpoints;
599
600         /* XXX try to share code with the counting loop! */
601
602         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
603                 /* skip dead code */
604
605                 if (bptr->flags < BBFINISHED)
606                         continue;
607
608                 /* get info about this block */
609
610                 m = bptr->method;
611                 iinfo = bptr->inlineinfo;
612
613                 /* initialize javalocals at the start of this block */
614
615                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
616
617                 /* create replacement points at targets of backward branches */
618
619                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
620
621                         i = (iinfo) ? iinfo->throughcount : 0;
622                         replace_create_replacement_point(jd, iinfo, rp++,
623                                         bptr->type, bptr->iinstr, &ra,
624                                         bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
625
626                         if (JITDATA_HAS_FLAG_COUNTDOWN(jd))
627                                 rp[-1].flags |= RPLPOINT_FLAG_COUNTDOWN;
628                 }
629
630                 /* iterate over the instructions */
631
632                 iptr = bptr->iinstr;
633                 iend = iptr + bptr->icount;
634
635                 for (; iptr != iend; ++iptr) {
636                         switch (iptr->opc) {
637 #if defined(ENABLE_GC_CACAO)
638                                 case ICMD_BUILTIN:
639                                         md = iptr->sx.s23.s3.bte->md;
640
641                                         i = (iinfo) ? iinfo->throughcount : 0;
642                                         replace_create_replacement_point(jd, iinfo, rp++,
643                                                         RPLPOINT_TYPE_CALL, iptr, &ra,
644                                                         javalocals, iptr->sx.s23.s2.args,
645                                                         iptr->s1.argcount - i,
646                                                         md->paramcount);
647                                         break;
648 #endif
649
650                                 case ICMD_INVOKESTATIC:
651                                 case ICMD_INVOKESPECIAL:
652                                 case ICMD_INVOKEVIRTUAL:
653                                 case ICMD_INVOKEINTERFACE:
654                                         INSTRUCTION_GET_METHODDESC(iptr, md);
655
656                                         i = (iinfo) ? iinfo->throughcount : 0;
657                                         replace_create_replacement_point(jd, iinfo, rp++,
658                                                         RPLPOINT_TYPE_CALL, iptr, &ra,
659                                                         javalocals, iptr->sx.s23.s2.args,
660                                                         iptr->s1.argcount - i,
661                                                         md->paramcount);
662                                         break;
663
664                                 case ICMD_ISTORE:
665                                 case ICMD_LSTORE:
666                                 case ICMD_FSTORE:
667                                 case ICMD_DSTORE:
668                                 case ICMD_ASTORE:
669                                         stack_javalocals_store(iptr, javalocals);
670                                         break;
671
672                                 case ICMD_IRETURN:
673                                 case ICMD_LRETURN:
674                                 case ICMD_FRETURN:
675                                 case ICMD_DRETURN:
676                                 case ICMD_ARETURN:
677                                         replace_create_replacement_point(jd, iinfo, rp++,
678                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
679                                                         NULL, &(iptr->s1.varindex), 1, 0);
680                                         break;
681
682                                 case ICMD_RETURN:
683                                         replace_create_replacement_point(jd, iinfo, rp++,
684                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
685                                                         NULL, NULL, 0, 0);
686                                         break;
687
688                                 case ICMD_INLINE_START:
689                                         iinfo = replace_create_inline_start_replacement_point(
690                                                                 jd, rp++, iptr, &ra, javalocals);
691                                         m = iinfo->method;
692                                         /* javalocals may be set at next block start, or now */
693                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
694                                         break;
695
696                                 case ICMD_INLINE_BODY:
697                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
698
699                                         jl = iinfo->javalocals_start;
700                                         if (jl == NULL) {
701                                                 /* get the javalocals from the following block start */
702                                                 assert(bptr->next);
703                                                 jl = bptr->next->javalocals;
704                                         }
705                                         /* create a non-trappable rplpoint */
706                                         replace_create_replacement_point(jd, iinfo, rp++,
707                                                         RPLPOINT_TYPE_BODY, iptr, &ra,
708                                                         jl, NULL, 0, 0);
709                                         rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
710                                         break;
711
712                                 case ICMD_INLINE_END:
713                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
714                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
715                                         iinfo = iptr->sx.s23.s3.inlineinfo;
716                                         m = iinfo->outer;
717                                         if (iinfo->javalocals_end)
718                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
719                                         iinfo = iinfo->parent;
720                                         break;
721                         }
722                 } /* end instruction loop */
723         } /* end basicblock loop */
724
725         assert((rp - rplpoints) == count);
726         assert((ra - regalloc) == alloccount);
727
728         /* store the data in the codeinfo */
729
730         code->rplpoints     = rplpoints;
731         code->rplpointcount = count;
732         code->regalloc      = regalloc;
733         code->regalloccount = alloccount;
734         code->globalcount   = 0;
735         code->savedintcount = INT_SAV_CNT - rd->savintreguse;
736         code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
737 #if defined(HAS_ADDRESS_REGISTER_FILE)
738         code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
739 #endif
740         code->memuse        = rd->memuse;
741         code->stackframesize = jd->cd->stackframesize;
742
743         REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
744         REPLACE_COUNT_INC(stat_regallocs, alloccount);
745
746         /* everything alright */
747
748         return true;
749 }
750
751
752 /* replace_free_replacement_points *********************************************
753  
754    Free memory used by replacement points.
755   
756    IN:
757        code.............codeinfo whose replacement points should be freed.
758   
759 *******************************************************************************/
760
761 void replace_free_replacement_points(codeinfo *code)
762 {
763         assert(code);
764
765         if (code->rplpoints)
766                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
767
768         if (code->regalloc)
769                 MFREE(code->regalloc,rplalloc,code->regalloccount);
770
771         code->rplpoints = NULL;
772         code->rplpointcount = 0;
773         code->regalloc = NULL;
774         code->regalloccount = 0;
775         code->globalcount = 0;
776 }
777
778
779 /******************************************************************************/
780 /* PART II: Activating / deactivating replacement points                      */
781 /******************************************************************************/
782
783
784 /* replace_activate_replacement_points *****************************************
785  
786    Activate the replacement points of the given compilation unit. When this
787    function returns, the replacement points are "armed", so each thread
788    reaching one of the points will enter the replacement mechanism.
789    
790    IN:
791        code.............codeinfo of which replacement points should be
792                                                 activated
793            mappable.........if true, only mappable replacement points are
794                                                 activated
795   
796 *******************************************************************************/
797
798 void replace_activate_replacement_points(codeinfo *code, bool mappable)
799 {
800         rplpoint *rp;
801         s4        i;
802         s4        count;
803         u1       *savedmcode;
804
805         assert(code->savedmcode == NULL);
806
807         /* count trappable replacement points */
808
809         count = 0;
810         i = code->rplpointcount;
811         rp = code->rplpoints;
812         for (; i--; rp++) {
813                 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
814                         continue;
815
816                 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
817                         continue;
818
819                 count++;
820         }
821
822         /* allocate buffer for saved machine code */
823
824         savedmcode = MNEW(u1, count * REPLACEMENT_PATCH_SIZE);
825         code->savedmcode = savedmcode;
826         savedmcode += count * REPLACEMENT_PATCH_SIZE;
827
828         /* activate trappable replacement points */
829         /* (in reverse order to handle overlapping points within basic blocks) */
830
831         i = code->rplpointcount;
832         rp = code->rplpoints + i;
833         while (rp--, i--) {
834                 assert(!(rp->flags & RPLPOINT_FLAG_ACTIVE));
835
836                 if (rp->flags & RPLPOINT_FLAG_NOTRAP)
837                         continue;
838
839                 if (mappable && (rp->type == RPLPOINT_TYPE_RETURN))
840                         continue;
841
842                 DOLOG( printf("activate replacement point:\n");
843                            replace_replacement_point_println(rp, 1); fflush(stdout); );
844
845                 savedmcode -= REPLACEMENT_PATCH_SIZE;
846
847 #if defined(ENABLE_JIT)
848 # if defined(ENABLE_DISASSEMBLER)
849                 DOLOG( printf("\tinstruction before: ");
850                            disassinstr(rp->pc); fflush(stdout); );
851 # endif
852
853                 md_patch_replacement_point(rp->pc, savedmcode, false);
854
855 # if defined(ENABLE_DISASSEMBLER)
856                 DOLOG( printf("\tinstruction after : ");
857                            disassinstr(rp->pc); fflush(stdout); );
858 # endif
859 #endif
860
861                 rp->flags |= RPLPOINT_FLAG_ACTIVE;
862         }
863
864         assert(savedmcode == code->savedmcode);
865 }
866
867
868 /* replace_deactivate_replacement_points ***************************************
869  
870    Deactivate a replacement points in the given compilation unit.
871    When this function returns, the replacement points will be "un-armed",
872    that is a each thread reaching a point will just continue normally.
873    
874    IN:
875        code.............the compilation unit
876   
877 *******************************************************************************/
878
879 void replace_deactivate_replacement_points(codeinfo *code)
880 {
881         rplpoint *rp;
882         s4        i;
883         s4        count;
884         u1       *savedmcode;
885
886         if (code->savedmcode == NULL) {
887                 /* disarm countdown points by patching the branches */
888
889                 i = code->rplpointcount;
890                 rp = code->rplpoints;
891                 for (; i--; rp++) {
892                         if ((rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))
893                                         == RPLPOINT_FLAG_COUNTDOWN)
894                         {
895 #if 0
896                                 *(s4*) (rp->pc + 9) = 0; /* XXX machine dependent! */
897 #endif
898                         }
899                 }
900                 return;
901         }
902
903         assert(code->savedmcode != NULL);
904         savedmcode = code->savedmcode;
905
906         /* de-activate each trappable replacement point */
907
908         i = code->rplpointcount;
909         rp = code->rplpoints;
910         count = 0;
911         for (; i--; rp++) {
912                 if (!(rp->flags & RPLPOINT_FLAG_ACTIVE))
913                         continue;
914
915                 count++;
916
917                 DOLOG( printf("deactivate replacement point:\n");
918                            replace_replacement_point_println(rp, 1); fflush(stdout); );
919
920 #if defined(ENABLE_JIT)
921 # if defined(ENABLE_DISASSEMBLER)
922                 DOLOG( printf("\tinstruction before: ");
923                            disassinstr(rp->pc); fflush(stdout); );
924 # endif
925
926                 md_patch_replacement_point(rp->pc, savedmcode, true);
927
928 # if defined(ENABLE_DISASSEMBLER)
929                 DOLOG( printf("\tinstruction before: ");
930                            disassinstr(rp->pc); fflush(stdout); );
931 # endif
932 #endif
933
934                 rp->flags &= ~RPLPOINT_FLAG_ACTIVE;
935
936                 savedmcode += REPLACEMENT_PATCH_SIZE;
937         }
938
939         assert(savedmcode == code->savedmcode + count * REPLACEMENT_PATCH_SIZE);
940
941         /* free saved machine code */
942
943         MFREE(code->savedmcode, u1, count * REPLACEMENT_PATCH_SIZE);
944         code->savedmcode = NULL;
945 }
946
947
948 /******************************************************************************/
949 /* PART III: The replacement mechanism                                        */
950 /******************************************************************************/
951
952
953 /* replace_read_value **********************************************************
954
955    Read a value with the given allocation from the execution state.
956    
957    IN:
958            es...............execution state
959            ra...............allocation
960            javaval..........where to put the value
961
962    OUT:
963        *javaval.........the value
964   
965 *******************************************************************************/
966
967 static void replace_read_value(executionstate_t *es,
968                                                            rplalloc *ra,
969                                                            replace_val_t *javaval)
970 {
971         if (ra->flags & INMEMORY) {
972                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
973 #ifdef HAS_4BYTE_STACKSLOT
974                 if (IS_2_WORD_TYPE(ra->type)) {
975                         javaval->l = *(u8*)(es->sp + ra->regoff);
976                 }
977                 else {
978 #endif
979                         javaval->p = *(ptrint*)(es->sp + ra->regoff);
980 #ifdef HAS_4BYTE_STACKSLOT
981                 }
982 #endif
983         }
984         else {
985                 /* allocated register */
986                 if (IS_FLT_DBL_TYPE(ra->type)) {
987                         javaval->d = es->fltregs[ra->regoff];
988
989                         if (ra->type == TYPE_FLT)
990                                 javaval->f = javaval->d;
991                 }
992 #if defined(HAS_ADDRESS_REGISTER_FILE)
993                 else if (IS_ADR_TYPE(ra->type)) {
994                         javaval->p = es->adrregs[ra->regoff];
995                 }
996 #endif
997                 else {
998 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
999                         if (ra->type == TYPE_LNG) {
1000                                 javaval->words.lo = es->intregs[GET_LOW_REG(ra->regoff)];
1001                                 javaval->words.hi = es->intregs[GET_HIGH_REG(ra->regoff)];
1002                         }
1003                         else
1004 #endif /* defined(SUPPORT_COMBINE_INTEGER_REGISTERS) */
1005                                 javaval->p = es->intregs[ra->regoff];
1006                 }
1007         }
1008 }
1009
1010
1011 /* replace_write_value *********************************************************
1012
1013    Write a value to the given allocation in the execution state.
1014    
1015    IN:
1016            es...............execution state
1017            ra...............allocation
1018            *javaval.........the value
1019
1020 *******************************************************************************/
1021
1022 static void replace_write_value(executionstate_t *es,
1023                                                             rplalloc *ra,
1024                                                             replace_val_t *javaval)
1025 {
1026         if (ra->flags & INMEMORY) {
1027                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
1028 #ifdef HAS_4BYTE_STACKSLOT
1029                 if (IS_2_WORD_TYPE(ra->type)) {
1030                         *(u8*)(es->sp + ra->regoff) = javaval->l;
1031                 }
1032                 else {
1033 #endif
1034                         *(ptrint*)(es->sp + ra->regoff) = javaval->p;
1035 #ifdef HAS_4BYTE_STACKSLOT
1036                 }
1037 #endif
1038         }
1039         else {
1040                 /* allocated register */
1041                 switch (ra->type) {
1042                         case TYPE_FLT:
1043                                 es->fltregs[ra->regoff] = (double) javaval->f;
1044                                 break;
1045                         case TYPE_DBL:
1046                                 es->fltregs[ra->regoff] = javaval->d;
1047                                 break;
1048 #if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
1049                         case TYPE_LNG:
1050                                 es->intregs[GET_LOW_REG(ra->regoff)] = javaval->words.lo;
1051                                 es->intregs[GET_HIGH_REG(ra->regoff)] = javaval->words.hi;
1052                                 break;
1053 #endif
1054 #if defined(HAS_ADDRESS_REGISTER_FILE)
1055                         case TYPE_ADR:
1056                                 es->adrregs[ra->regoff] = javaval->p;
1057 #endif
1058                         default:
1059                                 es->intregs[ra->regoff] = javaval->p;
1060                 }
1061         }
1062 }
1063
1064
1065 /* replace_new_sourceframe *****************************************************
1066
1067    Allocate a new source frame and insert it at the front of the frame list.
1068    
1069    IN:
1070            ss...............the source state
1071
1072    OUT:
1073            ss->frames.......set to new frame (the new head of the frame list).
1074
1075    RETURN VALUE:
1076        returns the new frame
1077
1078 *******************************************************************************/
1079
1080 static sourceframe_t *replace_new_sourceframe(sourcestate_t *ss)
1081 {
1082         sourceframe_t *frame;
1083
1084         frame = DNEW(sourceframe_t);
1085         MZERO(frame, sourceframe_t, 1);
1086
1087         frame->down = ss->frames;
1088         ss->frames = frame;
1089
1090         return frame;
1091 }
1092
1093
1094 /* replace_read_executionstate *************************************************
1095
1096    Read a source frame from the given executions state.
1097    The new source frame is pushed to the front of the frame list of the
1098    source state.
1099
1100    IN:
1101        rp...............replacement point at which `es` was taken
1102            es...............execution state
1103            ss...............the source state to add the source frame to
1104            topframe.........true, if the first (top-most) source frame on the
1105                             stack is to be read
1106
1107    OUT:
1108        *ss..............the source state with the newly created source frame
1109                             added
1110   
1111 *******************************************************************************/
1112
1113 static s4 replace_normalize_type_map[] = {
1114 /* RPLPOINT_TYPE_STD    |--> */ RPLPOINT_TYPE_STD,
1115 /* RPLPOINT_TYPE_EXH    |--> */ RPLPOINT_TYPE_STD,
1116 /* RPLPOINT_TYPE_SBR    |--> */ RPLPOINT_TYPE_STD,
1117 /* RPLPOINT_TYPE_CALL   |--> */ RPLPOINT_TYPE_CALL,
1118 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
1119 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
1120 /* RPLPOINT_TYPE_BODY   |--> */ RPLPOINT_TYPE_STD
1121 };
1122
1123
1124 static void replace_read_executionstate(rplpoint *rp,
1125                                                                                 executionstate_t *es,
1126                                                                                 sourcestate_t *ss,
1127                                                                                 bool topframe)
1128 {
1129         methodinfo    *m;
1130         codeinfo      *code;
1131         int            count;
1132         int            i;
1133         rplalloc      *ra;
1134         sourceframe_t *frame;
1135         int            topslot;
1136         stackslot_t   *sp;
1137         stackslot_t   *basesp;
1138
1139         code = code_find_codeinfo_for_pc(rp->pc);
1140         m = rp->method;
1141         topslot = TOP_IS_NORMAL;
1142
1143         /* stack pointer */
1144
1145         sp = (stackslot_t *) es->sp;
1146
1147         /* in some cases the top stack slot is passed in REG_ITMP1 */
1148
1149         if (rp->type == BBTYPE_EXH) {
1150                 topslot = TOP_IS_IN_ITMP1;
1151         }
1152
1153         /* calculate base stack pointer */
1154
1155         basesp = sp + code->stackframesize;
1156
1157         /* create the source frame */
1158
1159         frame = replace_new_sourceframe(ss);
1160         frame->method = rp->method;
1161         frame->id = rp->id;
1162         assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
1163         frame->type = replace_normalize_type_map[rp->type];
1164         frame->fromrp = rp;
1165         frame->fromcode = code;
1166
1167         /* read local variables */
1168
1169         count = m->maxlocals;
1170         frame->javalocalcount = count;
1171         frame->javalocals = DMNEW(replace_val_t, count);
1172         frame->javalocaltype = DMNEW(u1, count);
1173
1174         /* mark values as undefined */
1175         for (i=0; i<count; ++i) {
1176 #if !defined(NDEBUG)
1177                 frame->javalocals[i].l = (u8) 0x00dead0000dead00ULL;
1178 #endif
1179                 frame->javalocaltype[i] = TYPE_VOID;
1180         }
1181
1182         /* some entries in the intregs array are not meaningful */
1183         /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
1184 #if !defined(NDEBUG)
1185         es->intregs[REG_SP   ] = (ptrint) 0x11dead1111dead11ULL;
1186 #ifdef REG_PV
1187         es->intregs[REG_PV   ] = (ptrint) 0x11dead1111dead11ULL;
1188 #endif
1189 #endif /* !defined(NDEBUG) */
1190
1191         /* read javalocals */
1192
1193         count = rp->regalloccount;
1194         ra = rp->regalloc;
1195
1196         while (count && (i = ra->index) >= 0) {
1197                 assert(i < m->maxlocals);
1198                 frame->javalocaltype[i] = ra->type;
1199                 if (ra->type == TYPE_RET)
1200                         frame->javalocals[i].i = ra->regoff;
1201                 else
1202                         replace_read_value(es, ra, frame->javalocals + i);
1203                 ra++;
1204                 count--;
1205         }
1206
1207         /* read instance, if this is the first rplpoint */
1208
1209 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1210         if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1211 #if 1
1212                 /* we are at the start of the method body, so if local 0 is set, */
1213                 /* it is the instance.                                           */
1214                 if (frame->javalocaltype[0] == TYPE_ADR)
1215                         frame->instance = frame->javalocals[0];
1216 #else
1217                 rplalloc instra;
1218                 methoddesc *md;
1219
1220                 md = rp->method->parseddesc;
1221                 assert(md->params);
1222                 assert(md->paramcount >= 1);
1223                 instra.type = TYPE_ADR;
1224                 instra.regoff = md->params[0].regoff;
1225                 if (md->params[0].inmemory) {
1226                         instra.flags = INMEMORY;
1227                         instra.regoff += (1 + code->stackframesize) * SIZE_OF_STACKSLOT;
1228                 }
1229                 else {
1230                         instra.flags = 0;
1231                 }
1232                 replace_read_value(es, &instra, &(frame->instance));
1233 #endif
1234         }
1235 #if defined(__I386__)
1236         else if (!(rp->method->flags & ACC_STATIC)) {
1237                 /* On i386 we always pass the first argument on stack. */
1238                 frame->instance.a = *(java_object_t **)(basesp + 1);
1239         } 
1240 #endif
1241 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1242
1243         /* read stack slots */
1244
1245         frame->javastackdepth = count;
1246         frame->javastack = DMNEW(replace_val_t, count);
1247         frame->javastacktype = DMNEW(u1, count);
1248
1249 #if !defined(NDEBUG)
1250         /* mark values as undefined */
1251         for (i=0; i<count; ++i) {
1252                 frame->javastack[i].l = (u8) 0x00dead0000dead00ULL;
1253                 frame->javastacktype[i] = TYPE_VOID;
1254         }
1255 #endif /* !defined(NDEBUG) */
1256
1257         i = 0;
1258
1259         /* the first stack slot is special in SBR and EXH blocks */
1260
1261         if (topslot == TOP_IS_ON_STACK) {
1262                 assert(count);
1263
1264                 assert(ra->index == RPLALLOC_STACK);
1265                 assert(ra->type == TYPE_ADR);
1266                 frame->javastack[i].p = sp[-1];
1267                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1268                 count--;
1269                 i++;
1270                 ra++;
1271         }
1272         else if (topslot == TOP_IS_IN_ITMP1) {
1273                 assert(count);
1274
1275                 assert(ra->index == RPLALLOC_STACK);
1276                 assert(ra->type == TYPE_ADR);
1277                 frame->javastack[i].p = es->intregs[REG_ITMP1];
1278                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1279                 count--;
1280                 i++;
1281                 ra++;
1282         }
1283         else if (topslot == TOP_IS_VOID) {
1284                 assert(count);
1285
1286                 assert(ra->index == RPLALLOC_STACK);
1287                 frame->javastack[i].l = 0;
1288                 frame->javastacktype[i] = TYPE_VOID;
1289                 count--;
1290                 i++;
1291                 ra++;
1292         }
1293
1294         /* read remaining stack slots */
1295
1296         for (; count--; ra++) {
1297                 if (ra->index == RPLALLOC_SYNC) {
1298                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1299
1300                         /* only read synchronization slots when traversing an inline point */
1301
1302                         if (!topframe) {
1303                                 sourceframe_t *calleeframe = frame->down;
1304                                 assert(calleeframe);
1305                                 assert(calleeframe->syncslotcount == 0);
1306                                 assert(calleeframe->syncslots == NULL);
1307
1308                                 calleeframe->syncslotcount = 1;
1309                                 calleeframe->syncslots = DMNEW(replace_val_t, 1);
1310                                 replace_read_value(es,ra,calleeframe->syncslots);
1311                         }
1312
1313                         frame->javastackdepth--;
1314                         continue;
1315                 }
1316
1317                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1318
1319                 /* do not read parameters of calls down the call chain */
1320
1321                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1322                         frame->javastackdepth--;
1323                 }
1324                 else {
1325                         if (ra->type == TYPE_RET)
1326                                 frame->javastack[i].i = ra->regoff;
1327                         else
1328                                 replace_read_value(es,ra,frame->javastack + i);
1329                         frame->javastacktype[i] = ra->type;
1330                         i++;
1331                 }
1332         }
1333 }
1334
1335
1336 /* replace_write_executionstate ************************************************
1337
1338    Pop a source frame from the front of the frame list of the given source state
1339    and write its values into the execution state.
1340
1341    IN:
1342        rp...............replacement point for which execution state should be
1343                             created
1344            es...............the execution state to modify
1345            ss...............the given source state
1346            topframe.........true, if this is the last (top-most) source frame to be
1347                             translated
1348
1349    OUT:
1350        *es..............the execution state derived from the source state
1351   
1352 *******************************************************************************/
1353
1354 static void replace_write_executionstate(rplpoint *rp,
1355                                                                                  executionstate_t *es,
1356                                                                                  sourcestate_t *ss,
1357                                                                                  bool topframe)
1358 {
1359         methodinfo     *m;
1360         codeinfo       *code;
1361         int             count;
1362         int             i;
1363         rplalloc       *ra;
1364         sourceframe_t  *frame;
1365         int             topslot;
1366         stackslot_t    *sp;
1367         stackslot_t    *basesp;
1368
1369         code = code_find_codeinfo_for_pc(rp->pc);
1370         m = rp->method;
1371         topslot = TOP_IS_NORMAL;
1372
1373         /* pop a source frame */
1374
1375         frame = ss->frames;
1376         assert(frame);
1377         ss->frames = frame->down;
1378
1379         /* calculate stack pointer */
1380
1381         sp = (stackslot_t *) es->sp;
1382
1383         basesp = sp + code->stackframesize;
1384
1385         /* in some cases the top stack slot is passed in REG_ITMP1 */
1386
1387         if (rp->type == BBTYPE_EXH) {
1388                 topslot = TOP_IS_IN_ITMP1;
1389         }
1390
1391         /* write javalocals */
1392
1393         ra = rp->regalloc;
1394         count = rp->regalloccount;
1395
1396         while (count && (i = ra->index) >= 0) {
1397                 assert(i < m->maxlocals);
1398                 assert(i < frame->javalocalcount);
1399                 assert(ra->type == frame->javalocaltype[i]);
1400                 if (ra->type == TYPE_RET) {
1401                         /* XXX assert that it matches this rplpoint */
1402                 }
1403                 else
1404                         replace_write_value(es, ra, frame->javalocals + i);
1405                 count--;
1406                 ra++;
1407         }
1408
1409         /* write stack slots */
1410
1411         i = 0;
1412
1413         /* the first stack slot is special in SBR and EXH blocks */
1414
1415         if (topslot == TOP_IS_ON_STACK) {
1416                 assert(count);
1417
1418                 assert(ra->index == RPLALLOC_STACK);
1419                 assert(i < frame->javastackdepth);
1420                 assert(frame->javastacktype[i] == TYPE_ADR);
1421                 sp[-1] = frame->javastack[i].p;
1422                 count--;
1423                 i++;
1424                 ra++;
1425         }
1426         else if (topslot == TOP_IS_IN_ITMP1) {
1427                 assert(count);
1428
1429                 assert(ra->index == RPLALLOC_STACK);
1430                 assert(i < frame->javastackdepth);
1431                 assert(frame->javastacktype[i] == TYPE_ADR);
1432                 es->intregs[REG_ITMP1] = frame->javastack[i].p;
1433                 count--;
1434                 i++;
1435                 ra++;
1436         }
1437         else if (topslot == TOP_IS_VOID) {
1438                 assert(count);
1439
1440                 assert(ra->index == RPLALLOC_STACK);
1441                 assert(i < frame->javastackdepth);
1442                 assert(frame->javastacktype[i] == TYPE_VOID);
1443                 count--;
1444                 i++;
1445                 ra++;
1446         }
1447
1448         /* write remaining stack slots */
1449
1450         for (; count--; ra++) {
1451                 if (ra->index == RPLALLOC_SYNC) {
1452                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1453
1454                         /* only write synchronization slots when traversing an inline point */
1455
1456                         if (!topframe) {
1457                                 assert(frame->down);
1458                                 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1459                                 assert(frame->down->syncslots != NULL);
1460
1461                                 replace_write_value(es,ra,frame->down->syncslots);
1462                         }
1463                         continue;
1464                 }
1465
1466                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1467
1468                 /* do not write parameters of calls down the call chain */
1469
1470                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1471                         /* skip it */
1472                         /*
1473                         ra->index = RPLALLOC_PARAM;
1474                         replace_val_t v;
1475                         v.l = 0;
1476                         replace_write_value(es,ra,&v);
1477                         */
1478                 }
1479                 else {
1480                         assert(i < frame->javastackdepth);
1481                         assert(ra->type == frame->javastacktype[i]);
1482                         if (ra->type == TYPE_RET) {
1483                                 /* XXX assert that it matches this rplpoint */
1484                         }
1485                         else {
1486                                 replace_write_value(es,ra,frame->javastack + i);
1487                         }
1488                         i++;
1489                 }
1490         }
1491
1492         /* set new pc */
1493
1494         es->pc = rp->pc;
1495 }
1496
1497
1498 /* md_pop_stackframe ***********************************************************
1499
1500    Restore callee-saved registers (including the RA register),
1501    set the stack pointer to the next stackframe,
1502    set the PC to the return address of the popped frame.
1503
1504    *** This function imitates the effects of the method epilog ***
1505    *** and returning from the method call.                     ***
1506
1507    IN:
1508        es...............execution state
1509
1510    OUT:
1511        *es..............the execution state after popping the stack frame
1512                         NOTE: es->code and es->pv are NOT updated.
1513
1514 *******************************************************************************/
1515
1516 void md_pop_stackframe(executionstate_t *es)
1517 {
1518         u1 *ra;
1519         s4 ra_align_off;
1520         s4 reg;
1521         s4 i;
1522         stackslot_t *basesp;
1523         stackslot_t *sp;
1524
1525         assert(es->code);
1526
1527         /* alignment offset of RA */
1528
1529         ra_align_off = 0;
1530 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1531     if (es->code->stackframesize)
1532                 ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P;
1533 #endif
1534
1535         /* read the return address */
1536
1537 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1538         if (code_is_leafmethod(es->code))
1539                 ra = es->ra;
1540         else
1541 #endif
1542                 ra = md_stacktrace_get_returnaddress(es->sp,
1543                            SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off);
1544
1545         /* calculate the base of the stack frame */
1546
1547         sp = (stackslot_t *) es->sp;
1548         basesp = sp + es->code->stackframesize;
1549
1550         /* restore return address, if part of frame */
1551
1552 #if defined(REPLACE_RA_TOP_OF_FRAME)
1553 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1554         if (!code_is_leafmethod(es->code))
1555 #endif
1556                 es->ra = (u1*) (ptrint) *--basesp;
1557 #endif /* REPLACE_RA_TOP_OF_FRAME */
1558
1559 #if defined(REPLACE_RA_LINKAGE_AREA)
1560 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1561         if (!code_is_leafmethod(es->code))
1562 #endif
1563                 es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
1564 #endif /* REPLACE_RA_LINKAGE_AREA */
1565
1566         /* restore saved int registers */
1567
1568         reg = INT_REG_CNT;
1569         for (i=0; i<es->code->savedintcount; ++i) {
1570                 while (nregdescint[--reg] != REG_SAV)
1571                         ;
1572                 es->intregs[reg] = *--basesp;
1573         }
1574
1575         /* restore saved flt registers */
1576
1577         /* XXX align? */
1578         reg = FLT_REG_CNT;
1579         for (i=0; i<es->code->savedfltcount; ++i) {
1580                 while (nregdescfloat[--reg] != REG_SAV)
1581                         ;
1582                 basesp -= STACK_SLOTS_PER_FLOAT;
1583                 es->fltregs[reg] = *(double*)basesp;
1584         }
1585
1586 #if defined(HAS_ADDRESS_REGISTER_FILE)
1587         /* restore saved adr registers */
1588
1589         reg = ADR_REG_CNT;
1590         for (i=0; i<es->code->savedadrcount; ++i) {
1591                 while (nregdescadr[--reg] != REG_SAV)
1592                         ;
1593                 es->adrregs[reg] = *--basesp;
1594         }
1595 #endif
1596
1597         /* adjust the stackpointer */
1598
1599         es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1600
1601 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1602         es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */
1603 #endif
1604
1605         /* set the program counter to the return address */
1606
1607         es->pc = ra;
1608
1609         /* in debugging mode clobber non-saved registers */
1610
1611 #if !defined(NDEBUG)
1612         /* for debugging */
1613         for (i=0; i<INT_REG_CNT; ++i)
1614                 if (nregdescint[i] != REG_SAV)
1615                         es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
1616         for (i=0; i<FLT_REG_CNT; ++i)
1617                 if (nregdescfloat[i] != REG_SAV)
1618                         *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
1619 # if defined(HAS_ADDRESS_REGISTER_FILE)
1620         for (i=0; i<ADR_REG_CNT; ++i)
1621                 if (nregdescadr[i] != REG_SAV)
1622                         es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
1623 # endif
1624 #endif /* !defined(NDEBUG) */
1625 }
1626
1627
1628 /* md_push_stackframe **********************************************************
1629
1630    Save the given return address, build the new stackframe,
1631    and store callee-saved registers.
1632
1633    *** This function imitates the effects of a call and the ***
1634    *** method prolog of the callee.                         ***
1635
1636    IN:
1637        es...............execution state
1638        calleecode.......the code we are "calling"
1639        ra...............the return address to save
1640
1641    OUT:
1642        *es..............the execution state after pushing the stack frame
1643                         NOTE: es->pc, es->code, and es->pv are NOT updated.
1644
1645 *******************************************************************************/
1646
1647 void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra)
1648 {
1649         s4           reg;
1650         s4           i;
1651         stackslot_t *basesp;
1652         stackslot_t *sp;
1653
1654         assert(es);
1655         assert(calleecode);
1656
1657         /* write the return address */
1658
1659 #if defined(REPLACE_RA_BETWEEN_FRAMES)
1660         es->sp -= SIZEOF_VOID_P;
1661         *((void **)es->sp) = (void *) ra;
1662         if (calleecode->stackframesize)
1663                 es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P);
1664 #endif /* REPLACE_RA_BETWEEN_FRAMES */
1665
1666         es->ra = (u1*) (ptrint) ra;
1667
1668         /* build the stackframe */
1669
1670         DOLOG( printf("building stackframe of %d words at %p\n",
1671                                   calleecode->stackframesize, (void*)es->sp); );
1672
1673         sp = (stackslot_t *) es->sp;
1674         basesp = sp;
1675
1676         sp -= calleecode->stackframesize;
1677         es->sp = (u1*) sp;
1678
1679         /* in debug mode, invalidate stack frame first */
1680
1681         /* XXX may not invalidate linkage area used by native code! */
1682
1683 #if !defined(NDEBUG) && 0
1684         for (i=0; i< (basesp - sp) && i < 1; ++i) {
1685                 sp[i] = 0xdeaddeadU;
1686         }
1687 #endif
1688
1689 #if defined(__I386__)
1690         /* Stackslot 0 may contain the object instance for vftbl patching.
1691            Destroy it, so there's no undefined value used. */
1692         if ((basesp - sp) > 0) {
1693                 sp[0] = 0;
1694         }
1695 #endif
1696
1697         /* save the return address register */
1698
1699 #if defined(REPLACE_RA_TOP_OF_FRAME)
1700 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1701         if (!code_is_leafmethod(calleecode))
1702 #endif
1703                 *--basesp = (ptrint) ra;
1704 #endif /* REPLACE_RA_TOP_OF_FRAME */
1705
1706 #if defined(REPLACE_RA_LINKAGE_AREA)
1707 #if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
1708         if (!code_is_leafmethod(calleecode))
1709 #endif
1710                 basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
1711 #endif /* REPLACE_RA_LINKAGE_AREA */
1712
1713         /* save int registers */
1714
1715         reg = INT_REG_CNT;
1716         for (i=0; i<calleecode->savedintcount; ++i) {
1717                 while (nregdescint[--reg] != REG_SAV)
1718                         ;
1719                 *--basesp = es->intregs[reg];
1720
1721                 /* XXX may not clobber saved regs used by native code! */
1722 #if !defined(NDEBUG) && 0
1723                 es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1724 #endif
1725         }
1726
1727         /* save flt registers */
1728
1729         /* XXX align? */
1730         reg = FLT_REG_CNT;
1731         for (i=0; i<calleecode->savedfltcount; ++i) {
1732                 while (nregdescfloat[--reg] != REG_SAV)
1733                         ;
1734                 basesp -= STACK_SLOTS_PER_FLOAT;
1735                 *(double*)basesp = es->fltregs[reg];
1736
1737                 /* XXX may not clobber saved regs used by native code! */
1738 #if !defined(NDEBUG) && 0
1739                 *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
1740 #endif
1741         }
1742
1743 #if defined(HAS_ADDRESS_REGISTER_FILE)
1744         /* save adr registers */
1745
1746         reg = ADR_REG_CNT;
1747         for (i=0; i<calleecode->savedadrcount; ++i) {
1748                 while (nregdescadr[--reg] != REG_SAV)
1749                         ;
1750                 *--basesp = es->adrregs[reg];
1751
1752                 /* XXX may not clobber saved regs used by native code! */
1753 #if !defined(NDEBUG) && 0
1754                 es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
1755 #endif
1756         }
1757 #endif
1758 }
1759
1760
1761 /* replace_pop_activation_record ***********************************************
1762
1763    Peel a stack frame from the execution state.
1764
1765    *** This function imitates the effects of the method epilog ***
1766    *** and returning from the method call.                     ***
1767
1768    IN:
1769        es...............execution state
1770        frame............source frame, receives synchronization slots
1771
1772    OUT:
1773        *es..............the execution state after popping the stack frame
1774
1775    RETURN VALUE:
1776        the return address of the poped activation record
1777
1778 *******************************************************************************/
1779
1780 u1* replace_pop_activation_record(executionstate_t *es,
1781                                                                   sourceframe_t *frame)
1782 {
1783         u1 *ra;
1784         u1 *pv;
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         pv = md_codegen_get_pv_from_pc(ra);
1821         DOLOG( printf("PV = %p\n", (void*) 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 = 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                 && vftbl->table[pd->m->vftblindex] != &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 = 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   = (void*) (((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   = md_codegen_get_pv_from_pc(sfi->ra);
2386         es->pc   = (void*) (((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 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  */