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