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