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