Merged with tip.
[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 #if defined(ENABLE_TLH)
2872         printf("Replacing in %s/%s\n", rp->method->clazz->name->text, rp->method->name->text);
2873 #endif
2874
2875         /*if (strcmp(rp->method->clazz->name->text, "antlr/AlternativeElement") == 0 && strcmp(rp->method->name->text, "getAutoGenType") ==0) opt_TraceReplacement = 2; else opt_TraceReplacement = 0;*/
2876
2877         DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
2878                                  stat_replacements, (void*)THREADOBJECT,
2879                                  rp->id, (void*)rp);
2880                                  method_println(es->code->m); );
2881
2882         DOLOG( replace_replacement_point_println(rp, 1); );
2883
2884         REPLACE_COUNT(stat_replacements);
2885
2886         /* mark start of dump memory area */
2887
2888         DMARKER;
2889
2890         /* Get the stackframeinfo for the current thread. */
2891
2892         sfi = threads_get_current_stackframeinfo();
2893
2894         /* recover source state */
2895
2896         ss = replace_recover_source_state(rp, sfi, es);
2897
2898 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2899         /* if there is a collection pending, we assume the replacement point should
2900            suspend this thread */
2901
2902         if (gc_pending) {
2903
2904                 thread = THREADOBJECT;
2905
2906                 DOLOG_SHORT( printf("REPLACEMENT: Suspending thread for GC now!\n"); );
2907
2908                 /* map the sourcestate using the identity mapping */
2909                 replace_map_source_state_identity(ss);
2910
2911                 /* since we enter the same method again, we turn off rps now */
2912                 /* XXX michi: can we really do this? what if the rp was active before
2913                    we activated it for the gc? */
2914                 replace_deactivate_replacement_points(origcode);
2915
2916                 /* remember executionstate and sourcestate for this thread */
2917                 GC_EXECUTIONSTATE = es;
2918                 GC_SOURCESTATE    = ss;
2919
2920                 /* really suspend this thread now (PC = 0) */
2921                 threads_suspend_ack(NULL, NULL);
2922
2923                 DOLOG_SHORT( printf("REPLACEMENT: Resuming thread after GC now!\n"); );
2924
2925         } else {
2926 #endif /*defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)*/
2927
2928         /* map the source state */
2929
2930         if (!replace_map_source_state(ss))
2931                 vm_abort("exception during method replacement");
2932
2933         DOLOG( replace_sourcestate_println(ss); );
2934
2935         DOLOG_SHORT( replace_sourcestate_println_short(ss); );
2936
2937 #if !defined(NDEBUG)
2938         /* avoid infinite loops by self-replacement, only if not in testing mode */
2939
2940         if (!opt_TestReplacement) {
2941                 frame = ss->frames;
2942                 while (frame->down)
2943                         frame = frame->down;
2944
2945                 if (frame->torp == origrp) {
2946                         DOLOG_SHORT(
2947                                 printf("WARNING: identity replacement, turning off rps to avoid infinite loop\n");
2948                         );
2949                         replace_deactivate_replacement_points(origcode);
2950                 }
2951         }
2952 #endif
2953
2954 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
2955         }
2956 #endif
2957
2958         /* build the new execution state */
2959
2960         replace_build_execution_state(ss, es);
2961
2962 #if !defined(NDEBUG)
2963         /* continue execution after patched machine code, if testing mode enabled */
2964
2965         if (opt_TestReplacement)
2966                 es->pc += REPLACEMENT_PATCH_SIZE;
2967 #endif
2968
2969         /* release dump area */
2970
2971         DRELEASE;
2972 }
2973
2974
2975 /* replace_me_wrapper **********************************************************
2976
2977    This function is called by the signal handler. It determines if there
2978    is an active replacement point pending at the given PC and returns
2979    accordingly.
2980
2981    THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
2982
2983    IN:
2984        pc...............the program counter that triggered the replacement.
2985        context..........the context (machine state) to which the
2986                             replacement should be applied.
2987
2988    OUT:
2989        context..........the context after replacement finished.
2990
2991    RETURN VALUE:
2992        true.............replacement done, everything went ok
2993        false............no replacement done, context unchanged
2994
2995 *******************************************************************************/
2996
2997 bool replace_me_wrapper(u1 *pc, void *context)
2998 {
2999         codeinfo         *code;
3000         rplpoint         *rp;
3001         executionstate_t  es;
3002 #if defined(ENABLE_RT_TIMING)
3003         struct timespec time_start, time_end;
3004 #endif
3005
3006         /* search the codeinfo for the given PC */
3007
3008         code = code_find_codeinfo_for_pc(pc);
3009         assert(code);
3010
3011         /* search for a replacement point at the given PC */
3012
3013         rp = replace_find_replacement_point_for_pc(code, pc, (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN));
3014
3015         /* check if the replacement point belongs to given PC and is active */
3016
3017         if ((rp != NULL) && (rp->pc == pc)
3018             && (rp->flags & (RPLPOINT_FLAG_ACTIVE | RPLPOINT_FLAG_COUNTDOWN))) {
3019
3020                 DOLOG( printf("valid replacement point\n"); );
3021
3022 #if !defined(NDEBUG)
3023                 executionstate_sanity_check(context);
3024 #endif
3025
3026                 /* set codeinfo pointer in execution state */
3027
3028                 es.code = code;
3029
3030                 /* read execution state from current context */
3031
3032                 md_executionstate_read(&es, context);
3033
3034                 DOLOG( printf("REPLACEMENT READ: ");
3035                            executionstate_println(&es); );
3036
3037                 /* do the actual replacement */
3038
3039 #if defined(ENABLE_RT_TIMING)
3040                 RT_TIMING_GET_TIME(time_start);
3041 #endif
3042
3043                 replace_me(rp, &es);
3044
3045 #if defined(ENABLE_RT_TIMING)
3046                 RT_TIMING_GET_TIME(time_end);
3047                 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
3048 #endif
3049
3050                 /* write execution state to current context */
3051
3052                 md_executionstate_write(&es, context);
3053
3054                 DOLOG( printf("REPLACEMENT WRITE: ");
3055                            executionstate_println(&es); );
3056
3057                 /* new code is entered after returning */
3058
3059                 DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
3060                 return true;
3061         }
3062         else
3063                 return false;
3064 }
3065
3066
3067 /******************************************************************************/
3068 /* NOTE: Stuff specific to the exact GC is below.                             */
3069 /******************************************************************************/
3070
3071 #if defined(ENABLE_GC_CACAO)
3072 void replace_gc_from_native(threadobject *thread, u1 *pc, u1 *sp)
3073 {
3074         stackframeinfo_t *sfi;
3075         executionstate_t *es;
3076         sourcestate_t    *ss;
3077
3078         /* Get the stackframeinfo of this thread. */
3079
3080         assert(thread == THREADOBJECT);
3081
3082         sfi = threads_get_current_stackframeinfo();
3083
3084         /* create the execution state */
3085         es = DNEW(executionstate_t);
3086         es->pc = pc;
3087         es->sp = sp;
3088         es->pv = 0;      /* since we are in a native, PV is invalid! */
3089         es->code = NULL; /* since we are in a native, we do not have a codeinfo */
3090
3091         /* we assume we are in a native (no replacement point)! */
3092         ss = replace_recover_source_state(NULL, sfi, es);
3093
3094         /* map the sourcestate using the identity mapping */
3095         replace_map_source_state_identity(ss);
3096
3097         /* remember executionstate and sourcestate for this thread */
3098         GC_EXECUTIONSTATE = es;
3099         GC_SOURCESTATE    = ss;
3100 }
3101 #endif
3102
3103 #if defined(ENABLE_GC_CACAO)
3104 void replace_gc_into_native(threadobject *thread)
3105 {
3106         executionstate_t *es;
3107         sourcestate_t    *ss;
3108
3109         /* get the executionstate and sourcestate for the given thread */
3110         es = GC_EXECUTIONSTATE;
3111         ss = GC_SOURCESTATE;
3112
3113         /* rebuild the stack of the given thread */
3114         replace_build_execution_state(ss, es);
3115 }
3116 #endif
3117
3118
3119 /******************************************************************************/
3120 /* NOTE: No important code below.                                             */
3121 /******************************************************************************/
3122
3123
3124 /* statistics *****************************************************************/
3125
3126 #if defined(REPLACE_STATISTICS)
3127 static void print_freq(FILE *file,int *array,int limit)
3128 {
3129         int i;
3130         int sum = 0;
3131         int cum = 0;
3132         for (i=0; i<limit; ++i)
3133                 sum += array[i];
3134         sum += array[limit];
3135         for (i=0; i<limit; ++i) {
3136                 cum += array[i];
3137                 fprintf(file,"      %3d: %8d (cum %3d%%)\n",
3138                                 i, array[i], (sum) ? ((100*cum)/sum) : 0);
3139         }
3140         fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
3141 }
3142 #endif /* defined(REPLACE_STATISTICS) */
3143
3144
3145 #if defined(REPLACE_STATISTICS)
3146
3147 #define REPLACE_PRINT_DIST(name, array)                              \
3148     printf("    " name " distribution:\n");                          \
3149     print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
3150
3151 void replace_print_statistics(void)
3152 {
3153         printf("replacement statistics:\n");
3154         printf("    # of replacements:   %d\n", stat_replacements);
3155         printf("    # of frames:         %d\n", stat_frames);
3156         printf("    # of recompilations: %d\n", stat_recompile);
3157         printf("    patched static calls:%d\n", stat_staticpatch);
3158         printf("    unrolled inlines:    %d\n", stat_unroll_inline);
3159         printf("    unrolled calls:      %d\n", stat_unroll_call);
3160         REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
3161         REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
3162         REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
3163         REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
3164         REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
3165         REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
3166         REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
3167         REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
3168         REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
3169         REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
3170         printf("\n");
3171         printf("    # of methods:            %d\n", stat_methods);
3172         printf("    # of replacement points: %d\n", stat_rploints);
3173         printf("    # of regallocs:          %d\n", stat_regallocs);
3174         printf("        per rplpoint:        %f\n", (double)stat_regallocs / stat_rploints);
3175         printf("        per method:          %f\n", (double)stat_regallocs / stat_methods);
3176         REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
3177         printf("\n");
3178
3179 }
3180 #endif /* defined(REPLACE_STATISTICS) */
3181
3182
3183 #if defined(REPLACE_STATISTICS)
3184 static void replace_statistics_source_frame(sourceframe_t *frame)
3185 {
3186         int adr = 0;
3187         int ret = 0;
3188         int prim = 0;
3189         int vd = 0;
3190         int n = 0;
3191         int i;
3192
3193         for (i=0; i<frame->javalocalcount; ++i) {
3194                 switch (frame->javalocaltype[i]) {
3195                         case TYPE_ADR: adr++; break;
3196                         case TYPE_RET: ret++; break;
3197                         case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3198                         case TYPE_VOID: vd++; break;
3199                         default: assert(0);
3200                 }
3201                 n++;
3202         }
3203         REPLACE_COUNT_DIST(stat_dist_locals, n);
3204         REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
3205         REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
3206         REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
3207         REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
3208         adr = ret = prim = n = 0;
3209         for (i=0; i<frame->javastackdepth; ++i) {
3210                 switch (frame->javastacktype[i]) {
3211                         case TYPE_ADR: adr++; break;
3212                         case TYPE_RET: ret++; break;
3213                         case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
3214                 }
3215                 n++;
3216         }
3217         REPLACE_COUNT_DIST(stat_dist_stack, n);
3218         REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
3219         REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
3220         REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
3221 }
3222 #endif /* defined(REPLACE_STATISTICS) */
3223
3224
3225 /* debugging helpers **********************************************************/
3226
3227 /* replace_replacement_point_println *******************************************
3228  
3229    Print replacement point info.
3230   
3231    IN:
3232        rp...............the replacement point to print
3233   
3234 *******************************************************************************/
3235
3236 #if !defined(NDEBUG)
3237
3238 #define TYPECHAR(t)  (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
3239
3240 static char *replace_type_str[] = {
3241         "STD",
3242         "EXH",
3243         "SBR",
3244         "CALL",
3245         "INLINE",
3246         "RETURN",
3247         "BODY"
3248 };
3249
3250 void replace_replacement_point_println(rplpoint *rp, int depth)
3251 {
3252         int j;
3253         int index;
3254
3255         if (!rp) {
3256                 printf("(rplpoint *)NULL\n");
3257                 return;
3258         }
3259
3260         for (j=0; j<depth; ++j)
3261                 putchar('\t');
3262
3263         printf("rplpoint (id %d) %p pc:%p+%d type:%s",
3264                         rp->id, (void*)rp,rp->pc,rp->callsize,
3265                         replace_type_str[rp->type]);
3266         if (rp->flags & RPLPOINT_FLAG_NOTRAP)
3267                 printf(" NOTRAP");
3268         if (rp->flags & RPLPOINT_FLAG_COUNTDOWN)
3269                 printf(" COUNTDOWN");
3270         if (rp->flags & RPLPOINT_FLAG_ACTIVE)
3271                 printf(" ACTIVE");
3272         printf(" parent:%p\n", (void*)rp->parent);
3273         for (j=0; j<depth; ++j)
3274                 putchar('\t');
3275         printf("ra:%d = [",     rp->regalloccount);
3276
3277         for (j=0; j<rp->regalloccount; ++j) {
3278                 if (j)
3279                         putchar(' ');
3280                 index = rp->regalloc[j].index;
3281                 switch (index) {
3282                         case RPLALLOC_STACK: printf("S"); break;
3283                         case RPLALLOC_PARAM: printf("P"); break;
3284                         case RPLALLOC_SYNC : printf("Y"); break;
3285                         default: printf("%d", index);
3286                 }
3287                 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
3288                 if (rp->regalloc[j].type == TYPE_RET) {
3289                         printf("ret(L%03d)", rp->regalloc[j].regoff);
3290                 }
3291                 else {
3292                         show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
3293                 }
3294         }
3295
3296         printf("]\n");
3297         for (j=0; j<depth; ++j)
3298                 putchar('\t');
3299         printf("method: ");
3300         method_print(rp->method);
3301
3302         printf("\n");
3303 }
3304 #endif /* !defined(NDEBUG) */
3305
3306
3307 /* replace_show_replacement_points *********************************************
3308  
3309    Print replacement point info.
3310   
3311    IN:
3312        code.............codeinfo whose replacement points should be printed.
3313   
3314 *******************************************************************************/
3315
3316 #if !defined(NDEBUG)
3317 void replace_show_replacement_points(codeinfo *code)
3318 {
3319         int i;
3320         int depth;
3321         rplpoint *rp;
3322         rplpoint *parent;
3323
3324         if (!code) {
3325                 printf("(codeinfo *)NULL\n");
3326                 return;
3327         }
3328
3329         printf("\treplacement points: %d\n",code->rplpointcount);
3330
3331         printf("\ttotal allocations : %d\n",code->regalloccount);
3332         printf("\tsaved int regs    : %d\n",code->savedintcount);
3333         printf("\tsaved flt regs    : %d\n",code->savedfltcount);
3334 #if defined(HAS_ADDRESS_REGISTER_FILE)
3335         printf("\tsaved adr regs    : %d\n",code->savedadrcount);
3336 #endif
3337         printf("\tmemuse            : %d\n",code->memuse);
3338
3339         printf("\n");
3340
3341         for (i=0; i<code->rplpointcount; ++i) {
3342                 rp = code->rplpoints + i;
3343
3344                 depth = 1;
3345                 parent = rp->parent;
3346                 while (parent) {
3347                         depth++;
3348                         parent = parent->parent;
3349                 }
3350                 replace_replacement_point_println(rp, depth);
3351         }
3352 }
3353 #endif
3354
3355
3356 #if !defined(NDEBUG)
3357 static void java_value_print(s4 type, replace_val_t value)
3358 {
3359         java_object_t *obj;
3360         utf           *u;
3361
3362         printf("%016llx",(unsigned long long) value.l);
3363
3364         if (type < 0 || type > TYPE_RET)
3365                 printf(" <INVALID TYPE:%d>", type);
3366         else
3367                 printf(" %s", show_jit_type_names[type]);
3368
3369         if (type == TYPE_ADR && value.a != NULL) {
3370                 obj = value.a;
3371                 putchar(' ');
3372                 utf_display_printable_ascii_classname(obj->vftbl->clazz->name);
3373
3374                 if (obj->vftbl->clazz == class_java_lang_String) {
3375                         printf(" \"");
3376                         u = javastring_toutf(obj, false);
3377                         utf_display_printable_ascii(u);
3378                         printf("\"");
3379                 }
3380         }
3381         else if (type == TYPE_INT) {
3382                 printf(" %ld", (long) value.i);
3383         }
3384         else if (type == TYPE_LNG) {
3385                 printf(" %lld", (long long) value.l);
3386         }
3387         else if (type == TYPE_FLT) {
3388                 printf(" %f", value.f);
3389         }
3390         else if (type == TYPE_DBL) {
3391                 printf(" %f", value.d);
3392         }
3393 }
3394 #endif /* !defined(NDEBUG) */
3395
3396
3397 #if !defined(NDEBUG)
3398 void replace_source_frame_println(sourceframe_t *frame)
3399 {
3400         s4 i,j;
3401         s4 t;
3402
3403         if (REPLACE_IS_NATIVE_FRAME(frame)) {
3404                 printf("\tNATIVE\n");
3405                 printf("\tsfi: "); replace_stackframeinfo_println(frame->sfi);
3406                 printf("\tnativepc: %p\n", frame->nativepc);
3407                 printf("\tframesize: %d\n", frame->nativeframesize);
3408
3409                 j = 0;
3410                 for (i=0; i<INT_REG_CNT; ++i) {
3411                         if (nregdescint[i] == REG_SAV)
3412                                 printf("\t%s = %p\n", abi_registers_integer_name[i], (void*)frame->nativesavint[j++]);
3413                 }
3414
3415                 j = 0;
3416                 for (i=0; i<FLT_REG_CNT; ++i) {
3417                         if (nregdescfloat[i] == REG_SAV)
3418                                 printf("\tF%02d = %f\n", i, frame->nativesavflt[j++]);
3419                 }
3420
3421                 printf("\n");
3422                 return;
3423         }
3424
3425         printf("\t");
3426         method_println(frame->method);
3427         printf("\tid: %d\n", frame->id);
3428         printf("\ttype: %s\n", replace_type_str[frame->type]);
3429         printf("\n");
3430
3431         if (frame->instance.a) {
3432                 printf("\tinstance: ");
3433                 java_value_print(TYPE_ADR, frame->instance);
3434                 printf("\n");
3435         }
3436
3437         if (frame->javalocalcount) {
3438                 printf("\tlocals (%d):\n",frame->javalocalcount);
3439                 for (i=0; i<frame->javalocalcount; ++i) {
3440                         t = frame->javalocaltype[i];
3441                         if (t == TYPE_VOID) {
3442                                 printf("\tlocal[ %2d] = void\n",i);
3443                         }
3444                         else {
3445                                 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
3446                                 java_value_print(t, frame->javalocals[i]);
3447                                 printf("\n");
3448                         }
3449                 }
3450                 printf("\n");
3451         }
3452
3453         if (frame->javastackdepth) {
3454                 printf("\tstack (depth %d):\n",frame->javastackdepth);
3455                 for (i=0; i<frame->javastackdepth; ++i) {
3456                         t = frame->javastacktype[i];
3457                         if (t == TYPE_VOID) {
3458                                 printf("\tstack[%2d] = void", i);
3459                         }
3460                         else {
3461                                 printf("\tstack[%2d] = ",i);
3462                                 java_value_print(frame->javastacktype[i], frame->javastack[i]);
3463                                 printf("\n");
3464                         }
3465                 }
3466                 printf("\n");
3467         }
3468
3469         if (frame->syncslotcount) {
3470                 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
3471                 for (i=0; i<frame->syncslotcount; ++i) {
3472                         printf("\tslot[%2d] = ",i);
3473 #ifdef HAS_4BYTE_STACKSLOT
3474                         printf("%08lx\n",(unsigned long) frame->syncslots[i].p);
3475 #else
3476                         printf("%016llx\n",(unsigned long long) frame->syncslots[i].p);
3477 #endif
3478                 }
3479                 printf("\n");
3480         }
3481
3482         if (frame->fromcode) {
3483                 printf("\tfrom %p ", (void*)frame->fromcode);
3484                 method_println(frame->fromcode->m);
3485         }
3486         if (frame->tocode) {
3487                 printf("\tto %p ", (void*)frame->tocode);
3488                 method_println(frame->tocode->m);
3489         }
3490
3491         if (frame->fromrp) {
3492                 printf("\tfrom replacement point:\n");
3493                 replace_replacement_point_println(frame->fromrp, 2);
3494         }
3495         if (frame->torp) {
3496                 printf("\tto replacement point:\n");
3497                 replace_replacement_point_println(frame->torp, 2);
3498         }
3499
3500         printf("\n");
3501 }
3502 #endif /* !defined(NDEBUG) */
3503
3504
3505 /* replace_sourcestate_println *************************************************
3506  
3507    Print source state
3508   
3509    IN:
3510        ss...............the source state to print
3511   
3512 *******************************************************************************/
3513
3514 #if !defined(NDEBUG)
3515 void replace_sourcestate_println(sourcestate_t *ss)
3516 {
3517         int i;
3518         sourceframe_t *frame;
3519
3520         if (!ss) {
3521                 printf("(sourcestate_t *)NULL\n");
3522                 return;
3523         }
3524
3525         printf("sourcestate_t:\n");
3526
3527         for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
3528                 printf("    frame %d:\n", i);
3529                 replace_source_frame_println(frame);
3530         }
3531 }
3532 #endif
3533
3534
3535 /* replace_sourcestate_println_short *******************************************
3536
3537    Print a compact representation of the given source state.
3538
3539    IN:
3540        ss...............the source state to print
3541
3542 *******************************************************************************/
3543
3544 #if !defined(NDEBUG)
3545 void replace_sourcestate_println_short(sourcestate_t *ss)
3546 {
3547         sourceframe_t *frame;
3548
3549         for (frame = ss->frames; frame != NULL; frame = frame->down) {
3550                 printf("\t");
3551
3552                 if (REPLACE_IS_NATIVE_FRAME(frame)) {
3553                         printf("NATIVE (pc %p size %d) ",
3554                                    (void*)frame->nativepc, frame->nativeframesize);
3555                         replace_stackframeinfo_println(frame->sfi);
3556                         continue;
3557                 }
3558
3559                 if (frame->torp) {
3560                         printf("%c", (frame->torp == frame->fromrp) ? '=' : '+');
3561                 }
3562
3563                 printf("%s", replace_type_str[frame->fromrp->type]);
3564
3565                 if (frame->torp && frame->torp->type != frame->fromrp->type)
3566                         printf("->%s", replace_type_str[frame->torp->type]);
3567
3568                 if (frame->tocode != frame->fromcode)
3569                         printf(" (%p->%p/%d) ",
3570                                    (void*) frame->fromcode, (void*) frame->tocode,
3571                                    frame->fromrp->id);
3572                 else
3573                         printf(" (%p/%d) ", (void*) frame->fromcode, frame->fromrp->id);
3574
3575                 method_println(frame->method);
3576         }
3577 }
3578 #endif
3579
3580 #if !defined(NDEBUG)
3581 static void replace_stackframeinfo_println(stackframeinfo_t *sfi)
3582 {
3583         printf("prev=%p pv=%p sp=%p ra=%p xpc=%p method=",
3584                         (void*)sfi->prev, (void*)sfi->pv, (void*)sfi->sp,
3585                         (void*)sfi->ra, (void*)sfi->xpc);
3586
3587         if (sfi->code)
3588                 method_println(sfi->code->m);
3589         else
3590                 printf("(nil)\n");
3591 }
3592 #endif
3593
3594
3595 /*
3596  * These are local overrides for various environment variables in Emacs.
3597  * Please do not remove this and leave it at the end of the file, where
3598  * Emacs will automagically detect them.
3599  * ---------------------------------------------------------------------
3600  * Local variables:
3601  * mode: c
3602  * indent-tabs-mode: t
3603  * c-basic-offset: 4
3604  * tab-width: 4
3605  * End:
3606  * vim:noexpandtab:sw=4:ts=4:
3607  */