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