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