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