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