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