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