* src/vm/jit/i386/emit.c (emit_verbosecall_enter): Check for
[cacao.git] / src / vm / jit / replace.c
1 /* vm/jit/replace.c - on-stack replacement of methods
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Edwin Steiner
28
29    Changes:
30
31    $Id$
32
33 */
34
35 #include "config.h"
36 #include "vm/types.h"
37
38 #include <assert.h>
39 #include <stdlib.h>
40
41 #include "arch.h"
42
43 #include "mm/memory.h"
44 #include "toolbox/logging.h"
45 #include "vm/options.h"
46 #include "vm/stringlocal.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/jit.h"
49 #include "vm/jit/replace.h"
50 #include "vm/jit/stack.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/disass.h"
53 #include "vm/jit/show.h"
54 #include "vm/jit/methodheader.h"
55
56 #include "native/include/java_lang_String.h"
57
58 #define REPLACE_PATCH_DYNAMIC_CALL
59 /*#define REPLACE_PATCH_ALL*/
60
61
62 /*** configuration of native stack slot size **********************************/
63
64 /* XXX this should be in md-abi.h files, probably */
65
66 #if defined(HAS_4BYTE_STACKSLOT)
67 #define SIZE_OF_STACKSLOT      4
68 #define STACK_SLOTS_PER_FLOAT  2
69 typedef u4 stackslot_t;
70 #else
71 #define SIZE_OF_STACKSLOT      8
72 #define STACK_SLOTS_PER_FLOAT  1
73 typedef u8 stackslot_t;
74 #endif
75
76
77 /*** debugging ****************************************************************/
78
79 /*#define REPLACE_VERBOSE*/
80
81 #if !defined(NDEBUG)
82 void java_value_print(s4 type, u8 value);
83
84 static char *replace_type_str[] = {
85         "STD",
86         "EXH",
87         "SBR",
88         "CALL",
89         "INLINE",
90         "RETURN",
91         "BODY"
92 };
93 #endif /* !defined(NDEBUG) */
94
95 #if !defined(NDEBUG) && defined(REPLACE_VERBOSE)
96 #define DOLOG(code) do{ if (1) { code; } } while(0)
97 #define DOLOG_SHORT(code) do{ if (1) { code; } } while(0)
98 #else
99 #define DOLOG(code)
100 #define DOLOG_SHORT(code)
101 #endif
102
103
104 /*** statistics ***************************************************************/
105
106 #define REPLACE_STATISTICS
107
108 #if defined(REPLACE_STATISTICS)
109
110 static int stat_replacements = 0;
111 static int stat_frames = 0;
112 static int stat_recompile = 0;
113 static int stat_staticpatch = 0;
114 static int stat_unroll_inline = 0;
115 static int stat_unroll_call = 0;
116 static int stat_dist_frames[20] = { 0 };
117 static int stat_dist_locals[20] = { 0 };
118 static int stat_dist_locals_adr[10] = { 0 };
119 static int stat_dist_locals_prim[10] = { 0 };
120 static int stat_dist_locals_ret[10] = { 0 };
121 static int stat_dist_locals_void[10] = { 0 };
122 static int stat_dist_stack[10] = { 0 };
123 static int stat_dist_stack_adr[10] = { 0 };
124 static int stat_dist_stack_prim[10] = { 0 };
125 static int stat_dist_stack_ret[10] = { 0 };
126 static int stat_methods = 0;
127 static int stat_rploints = 0;
128 static int stat_regallocs = 0;
129 static int stat_dist_method_rplpoints[20] = { 0 };
130
131 #define REPLACE_COUNT(cnt)  (cnt)++
132 #define REPLACE_COUNT_IF(cnt, cond)  do{ if(cond) (cnt)++; } while(0)
133 #define REPLACE_COUNT_INC(cnt, inc)  ((cnt) += (inc))
134
135 #define REPLACE_COUNT_DIST(array, val)                               \
136     do {                                                             \
137         int limit = (sizeof(array) / sizeof(int)) - 1;               \
138         if ((val) < (limit)) (array)[val]++;                         \
139         else (array)[limit]++;                                       \
140     } while (0)
141
142 #define REPLACE_PRINT_DIST(name, array) \
143         printf("    " name " distribution:\n"); \
144         print_freq(stdout, (array), sizeof(array)/sizeof(int) - 1);
145
146 static void print_freq(FILE *file,int *array,int limit)
147 {
148         int i;
149         int sum = 0;
150         int cum = 0;
151         for (i=0; i<limit; ++i)
152                 sum += array[i];
153         sum += array[limit];
154         for (i=0; i<limit; ++i) {
155                 cum += array[i];
156                 fprintf(file,"      %3d: %8d (cum %3d%%)\n",
157                                 i, array[i], (sum) ? ((100*cum)/sum) : 0);
158         }
159         fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
160 }
161
162 void replace_print_statistics(void)
163 {
164         printf("replacement statistics:\n");
165         printf("    # of replacements:   %d\n", stat_replacements);
166         printf("    # of frames:         %d\n", stat_frames);
167         printf("    # of recompilations: %d\n", stat_recompile);
168         printf("    patched static calls:%d\n", stat_staticpatch);
169         printf("    unrolled inlines:    %d\n", stat_unroll_inline);
170         printf("    unrolled calls:      %d\n", stat_unroll_call);
171         REPLACE_PRINT_DIST("frame depth", stat_dist_frames);
172         REPLACE_PRINT_DIST("locals per frame", stat_dist_locals);
173         REPLACE_PRINT_DIST("ADR locals per frame", stat_dist_locals_adr);
174         REPLACE_PRINT_DIST("primitive locals per frame", stat_dist_locals_prim);
175         REPLACE_PRINT_DIST("RET locals per frame", stat_dist_locals_ret);
176         REPLACE_PRINT_DIST("void locals per frame", stat_dist_locals_void);
177         REPLACE_PRINT_DIST("stack slots per frame", stat_dist_stack);
178         REPLACE_PRINT_DIST("ADR stack slots per frame", stat_dist_stack_adr);
179         REPLACE_PRINT_DIST("primitive stack slots per frame", stat_dist_stack_prim);
180         REPLACE_PRINT_DIST("RET stack slots per frame", stat_dist_stack_ret);
181         printf("\n");
182         printf("    # of methods:            %d\n", stat_methods);
183         printf("    # of replacement points: %d\n", stat_rploints);
184         printf("    # of regallocs:          %d\n", stat_regallocs);
185         printf("        per rplpoint:        %f\n", (double)stat_regallocs / stat_rploints);
186         printf("        per method:          %f\n", (double)stat_regallocs / stat_methods);
187         REPLACE_PRINT_DIST("replacement points per method", stat_dist_method_rplpoints);
188         printf("\n");
189
190 }
191
192 #else
193
194 #define REPLACE_COUNT(cnt)
195 #define REPLACE_COUNT_IF(cnt, cond)
196 #define REPLACE_COUNT_INC(cnt, inc)
197 #define REPLACE_COUNT_DIST(array, val)
198
199 #endif /* defined(REPLACE_STATISTICS) */
200
201 /*** constants used internally ************************************************/
202
203 #define TOP_IS_NORMAL    0
204 #define TOP_IS_ON_STACK  1
205 #define TOP_IS_IN_ITMP1  2
206 #define TOP_IS_VOID      3
207
208
209 /* replace_create_replacement_point ********************************************
210  
211    Create a replacement point.
212   
213    IN:
214        jd...............current jitdata
215            iinfo............inlining info for the current position
216            rp...............pre-allocated (uninitialized) rplpoint
217            type.............RPLPOINT_TYPE constant
218            iptr.............current instruction
219            *pra.............current rplalloc pointer
220            javalocals.......the javalocals at the current point
221            stackvars........the stack variables at the current point
222            stackdepth.......the stack depth at the current point
223            paramcount.......number of parameters at the start of stackvars
224   
225    OUT:
226        *rpa.............points to the next free rplalloc
227   
228 *******************************************************************************/
229
230 static void replace_create_replacement_point(jitdata *jd,
231                                                                                          insinfo_inline *iinfo,
232                                                                                          rplpoint *rp,
233                                                                                          s4 type,
234                                                                                          instruction *iptr,
235                                                                                          rplalloc **pra,
236                                                                                          s4 *javalocals,
237                                                                                          s4 *stackvars,
238                                                                                          s4 stackdepth,
239                                                                                          s4 paramcount)
240 {
241         rplalloc *ra;
242         s4        i;
243         varinfo  *v;
244         s4        index;
245
246         ra = *pra;
247
248         REPLACE_COUNT(stat_rploints);
249
250         rp->method = (iinfo) ? iinfo->method : jd->m;
251         rp->pc = NULL;        /* set by codegen */
252         rp->outcode = NULL;   /* set by codegen */
253         rp->callsize = 0;     /* set by codegen */
254         rp->target = NULL;
255         rp->regalloc = ra;
256         rp->flags = 0;
257         rp->type = type;
258         rp->id = iptr->flags.bits >> INS_FLAG_ID_SHIFT;
259
260         /* XXX unify these two fields */
261         rp->code = jd->code;
262         rp->parent = (iinfo) ? iinfo->rp : NULL;
263
264         /* store local allocation info of javalocals */
265
266         if (javalocals) {
267                 for (i = 0; i < rp->method->maxlocals; ++i) {
268                         index = javalocals[i];
269                         if (index == UNUSED)
270                                 continue;
271
272                         ra->index = i;
273                         if (index < UNUSED) {
274                                 ra->regoff = (UNUSED - index) - 1;
275                                 ra->type = TYPE_RET;
276                                 ra->flags = 0;
277                         }
278                         else {
279                                 v = VAR(index);
280                                 ra->flags = v->flags & (INMEMORY);
281                                 ra->regoff = v->vv.regoff;
282                                 ra->type = v->type;
283                         }
284                         ra++;
285                 }
286         }
287
288         /* store allocation info of java stack vars */
289
290         for (i = 0; i < stackdepth; ++i) {
291                 v = VAR(stackvars[i]);
292                 ra->flags = v->flags & (INMEMORY);
293                 ra->index = (i < paramcount) ? RPLALLOC_PARAM : RPLALLOC_STACK;
294                 ra->type  = v->type;
295                 /* XXX how to handle locals on the stack containing returnAddresses? */
296                 if (v->type == TYPE_RET) {
297                         assert(stackvars[i] >= jd->localcount);
298                         ra->regoff = v->vv.retaddr->nr;
299                 }
300                 else
301                         ra->regoff = v->vv.regoff;
302                 ra++;
303         }
304
305         /* total number of allocations */
306
307         rp->regalloccount = ra - rp->regalloc;
308
309         *pra = ra;
310 }
311
312
313 /* replace_create_inline_start_replacement_point *******************************
314
315    Create an INLINE_START replacement point.
316
317    IN:
318        jd...............current jitdata
319            rp...............pre-allocated (uninitialized) rplpoint
320            iptr.............current instruction
321            *pra.............current rplalloc pointer
322            javalocals.......the javalocals at the current point
323
324    OUT:
325        *rpa.............points to the next free rplalloc
326
327    RETURN VALUE:
328        the insinfo_inline * for the following inlined body
329
330 *******************************************************************************/
331
332 static insinfo_inline * replace_create_inline_start_replacement_point(
333                                                                                          jitdata *jd,
334                                                                                          rplpoint *rp,
335                                                                                          instruction *iptr,
336                                                                                          rplalloc **pra,
337                                                                                          s4 *javalocals)
338 {
339         insinfo_inline *calleeinfo;
340         rplalloc       *ra;
341
342         calleeinfo = iptr->sx.s23.s3.inlineinfo;
343
344         calleeinfo->rp = rp;
345
346         replace_create_replacement_point(jd, calleeinfo->parent, rp,
347                         RPLPOINT_TYPE_INLINE, iptr, pra,
348                         javalocals,
349                         calleeinfo->stackvars, calleeinfo->stackvarscount,
350                         calleeinfo->paramcount);
351
352         if (calleeinfo->synclocal != UNUSED) {
353                 ra = (*pra)++;
354                 ra->index  = RPLALLOC_SYNC;
355                 ra->regoff = jd->var[calleeinfo->synclocal].vv.regoff;
356                 ra->flags  = jd->var[calleeinfo->synclocal].flags & INMEMORY;
357                 ra->type   = TYPE_ADR;
358
359                 rp->regalloccount++;
360         }
361
362         return calleeinfo;
363 }
364
365
366 /* replace_create_replacement_points *******************************************
367  
368    Create the replacement points for the given code.
369   
370    IN:
371        jd...............current jitdata, must not have any replacement points
372   
373    OUT:
374        code->rplpoints.......set to the list of replacement points
375            code->rplpointcount...number of replacement points
376            code->regalloc........list of allocation info
377            code->regalloccount...total length of allocation info list
378            code->globalcount.....number of global allocations at the
379                                  start of code->regalloc
380   
381    RETURN VALUE:
382        true.............everything ok 
383        false............an exception has been thrown
384    
385 *******************************************************************************/
386
387 #define CLEAR_javalocals(array, method)                              \
388     do {                                                             \
389         for (i=0; i<(method)->maxlocals; ++i)                        \
390             (array)[i] = UNUSED;                                     \
391     } while (0)
392
393 #define COPY_OR_CLEAR_javalocals(dest, array, method)                \
394     do {                                                             \
395         if ((array) != NULL)                                         \
396             MCOPY((dest), (array), s4, (method)->maxlocals);         \
397         else                                                         \
398             CLEAR_javalocals((dest), (method));                      \
399     } while (0)
400
401 #define COUNT_javalocals(array, method, counter)                     \
402     do {                                                             \
403         for (i=0; i<(method)->maxlocals; ++i)                        \
404             if ((array)[i] != UNUSED)                                \
405                                 (counter)++;                                         \
406     } while (0)
407
408 bool replace_create_replacement_points(jitdata *jd)
409 {
410         codeinfo        *code;
411         registerdata    *rd;
412         basicblock      *bptr;
413         int              count;
414         methodinfo      *m;
415         rplpoint        *rplpoints;
416         rplpoint        *rp;
417         int              alloccount;
418         rplalloc        *regalloc;
419         rplalloc        *ra;
420         int              i;
421         instruction     *iptr;
422         instruction     *iend;
423         s4              *javalocals;
424         s4              *jl;
425         methoddesc      *md;
426         insinfo_inline  *iinfo;
427         s4               startcount;
428         s4               firstcount;
429 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
430         bool             needentry;
431 #endif
432
433         REPLACE_COUNT(stat_methods);
434
435         /* get required compiler data */
436
437         code = jd->code;
438         rd   = jd->rd;
439
440         /* assert that we wont overwrite already allocated data */
441
442         assert(code);
443         assert(code->m);
444         assert(code->rplpoints == NULL);
445         assert(code->rplpointcount == 0);
446         assert(code->regalloc == NULL);
447         assert(code->regalloccount == 0);
448         assert(code->globalcount == 0);
449
450         m = code->m;
451
452         /* in instance methods, we may need a rplpoint at the method entry */
453
454 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
455         if (!(m->flags & ACC_STATIC)) {
456                 jd->basicblocks[0].bitflags |= BBFLAG_REPLACEMENT;
457                 needentry = true;
458         }
459         else {
460                 needentry = false;
461         }
462 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
463
464         /* iterate over the basic block list to find replacement points */
465
466         count = 0;
467         alloccount = 0;
468
469         javalocals = DMNEW(s4, jd->maxlocals);
470
471         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
472
473                 /* skip dead code */
474
475                 if (bptr->flags < BBFINISHED)
476                         continue;
477
478                 /* get info about this block */
479
480                 m = bptr->method;
481                 iinfo = bptr->inlineinfo;
482
483                 /* initialize javalocals at the start of this block */
484
485                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
486
487                 /* iterate over the instructions */
488
489                 iptr = bptr->iinstr;
490                 iend = iptr + bptr->icount;
491                 startcount = count;
492                 firstcount = count;
493
494                 for (; iptr != iend; ++iptr) {
495                         switch (iptr->opc) {
496                                 case ICMD_INVOKESTATIC:
497                                 case ICMD_INVOKESPECIAL:
498                                 case ICMD_INVOKEVIRTUAL:
499                                 case ICMD_INVOKEINTERFACE:
500                                         INSTRUCTION_GET_METHODDESC(iptr, md);
501                                         count++;
502                                         COUNT_javalocals(javalocals, m, alloccount);
503                                         alloccount += iptr->s1.argcount;
504                                         if (iinfo)
505                                                 alloccount -= iinfo->throughcount;
506                                         break;
507
508                                 case ICMD_ISTORE:
509                                 case ICMD_LSTORE:
510                                 case ICMD_FSTORE:
511                                 case ICMD_DSTORE:
512                                 case ICMD_ASTORE:
513                                         stack_javalocals_store(iptr, javalocals);
514                                         break;
515
516                                 case ICMD_IRETURN:
517                                 case ICMD_LRETURN:
518                                 case ICMD_FRETURN:
519                                 case ICMD_DRETURN:
520                                 case ICMD_ARETURN:
521                                         alloccount += 1;
522                                         /* FALLTHROUGH! */
523                                 case ICMD_RETURN:
524                                         count++;
525                                         break;
526
527                                 case ICMD_INLINE_START:
528                                         iinfo = iptr->sx.s23.s3.inlineinfo;
529
530                                         count++;
531                                         COUNT_javalocals(javalocals, m, alloccount);
532                                         alloccount += iinfo->stackvarscount;
533                                         if (iinfo->synclocal != UNUSED)
534                                                 alloccount++;
535
536                                         m = iinfo->method;
537                                         /* javalocals may be set at next block start, or now */
538                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
539                                         break;
540
541                                 case ICMD_INLINE_BODY:
542                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
543
544                                         jl = iinfo->javalocals_start;
545                                         if (jl == NULL) {
546                                                 /* get the javalocals from the following block start */
547                                                 assert(bptr->next);
548                                                 jl = bptr->next->javalocals;
549                                         }
550                                         count++;
551                                         COUNT_javalocals(jl, m, alloccount);
552                                         break;
553
554                                 case ICMD_INLINE_END:
555                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
556                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
557                                         iinfo = iptr->sx.s23.s3.inlineinfo;
558                                         m = iinfo->outer;
559                                         if (iinfo->javalocals_end)
560                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
561                                         iinfo = iinfo->parent;
562                                         break;
563                         }
564
565                         if (iptr == bptr->iinstr)
566                                 firstcount = count;
567                 } /* end instruction loop */
568
569                 /* create replacement points at targets of backward branches */
570                 /* We only need the replacement point there, if there is no  */
571                 /* replacement point inside the block.                       */
572
573                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
574 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
575                         int test = (needentry && bptr == jd->basicblocks) ? firstcount : count;
576 #else
577                         int test = count;
578 #endif
579                         if (test > startcount) {
580                                 /* we don't need an extra rplpoint */
581                                 bptr->bitflags &= ~BBFLAG_REPLACEMENT;
582                         }
583                         else {
584                                 count++;
585                                 alloccount += bptr->indepth;
586                                 if (bptr->inlineinfo)
587                                         alloccount -= bptr->inlineinfo->throughcount;
588
589                                 COUNT_javalocals(bptr->javalocals, bptr->method, alloccount);
590                         }
591                 }
592
593         } /* end basicblock loop */
594
595         /* if no points were found, there's nothing to do */
596
597         if (!count)
598                 return true;
599
600         /* allocate replacement point array and allocation array */
601
602         rplpoints = MNEW(rplpoint, count);
603         regalloc = MNEW(rplalloc, alloccount);
604         ra = regalloc;
605
606         /* initialize replacement point structs */
607
608         rp = rplpoints;
609
610         /* XXX try to share code with the counting loop! */
611
612         for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
613                 /* skip dead code */
614
615                 if (bptr->flags < BBFINISHED)
616                         continue;
617
618                 /* get info about this block */
619
620                 m = bptr->method;
621                 iinfo = bptr->inlineinfo;
622
623                 /* initialize javalocals at the start of this block */
624
625                 COPY_OR_CLEAR_javalocals(javalocals, bptr->javalocals, m);
626
627                 /* create replacement points at targets of backward branches */
628
629                 if (bptr->bitflags & BBFLAG_REPLACEMENT) {
630
631                         i = (iinfo) ? iinfo->throughcount : 0;
632                         replace_create_replacement_point(jd, iinfo, rp++,
633                                         bptr->type, bptr->iinstr, &ra,
634                                         bptr->javalocals, bptr->invars + i, bptr->indepth - i, 0);
635                 }
636
637                 /* iterate over the instructions */
638
639                 iptr = bptr->iinstr;
640                 iend = iptr + bptr->icount;
641
642                 for (; iptr != iend; ++iptr) {
643                         switch (iptr->opc) {
644                                 case ICMD_INVOKESTATIC:
645                                 case ICMD_INVOKESPECIAL:
646                                 case ICMD_INVOKEVIRTUAL:
647                                 case ICMD_INVOKEINTERFACE:
648                                         INSTRUCTION_GET_METHODDESC(iptr, md);
649
650                                         i = (iinfo) ? iinfo->throughcount : 0;
651                                         replace_create_replacement_point(jd, iinfo, rp++,
652                                                         RPLPOINT_TYPE_CALL, iptr, &ra,
653                                                         javalocals, iptr->sx.s23.s2.args,
654                                                         iptr->s1.argcount - i,
655                                                         md->paramcount);
656                                         break;
657
658                                 case ICMD_ISTORE:
659                                 case ICMD_LSTORE:
660                                 case ICMD_FSTORE:
661                                 case ICMD_DSTORE:
662                                 case ICMD_ASTORE:
663                                         stack_javalocals_store(iptr, javalocals);
664                                         break;
665
666                                 case ICMD_IRETURN:
667                                 case ICMD_LRETURN:
668                                 case ICMD_FRETURN:
669                                 case ICMD_DRETURN:
670                                 case ICMD_ARETURN:
671                                         replace_create_replacement_point(jd, iinfo, rp++,
672                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
673                                                         NULL, &(iptr->s1.varindex), 1, 0);
674                                         break;
675
676                                 case ICMD_RETURN:
677                                         replace_create_replacement_point(jd, iinfo, rp++,
678                                                         RPLPOINT_TYPE_RETURN, iptr, &ra,
679                                                         NULL, NULL, 0, 0);
680                                         break;
681
682                                 case ICMD_INLINE_START:
683                                         iinfo = replace_create_inline_start_replacement_point(
684                                                                 jd, rp++, iptr, &ra, javalocals);
685                                         m = iinfo->method;
686                                         /* javalocals may be set at next block start, or now */
687                                         COPY_OR_CLEAR_javalocals(javalocals, iinfo->javalocals_start, m);
688                                         break;
689
690                                 case ICMD_INLINE_BODY:
691                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo);
692
693                                         jl = iinfo->javalocals_start;
694                                         if (jl == NULL) {
695                                                 /* get the javalocals from the following block start */
696                                                 assert(bptr->next);
697                                                 jl = bptr->next->javalocals;
698                                         }
699                                         /* create a non-trappable rplpoint */
700                                         replace_create_replacement_point(jd, iinfo, rp++,
701                                                         RPLPOINT_TYPE_BODY, iptr, &ra,
702                                                         jl, NULL, 0, 0);
703                                         rp[-1].flags |= RPLPOINT_FLAG_NOTRAP;
704                                         break;
705
706                                 case ICMD_INLINE_END:
707                                         assert(iinfo == iptr->sx.s23.s3.inlineinfo ||
708                                                    iinfo == iptr->sx.s23.s3.inlineinfo->parent);
709                                         iinfo = iptr->sx.s23.s3.inlineinfo;
710                                         m = iinfo->outer;
711                                         if (iinfo->javalocals_end)
712                                                 MCOPY(javalocals, iinfo->javalocals_end, s4, m->maxlocals);
713                                         iinfo = iinfo->parent;
714                                         break;
715                         }
716                 } /* end instruction loop */
717         } /* end basicblock loop */
718
719         assert((rp - rplpoints) == count);
720         assert((ra - regalloc) == alloccount);
721
722         /* store the data in the codeinfo */
723
724         code->rplpoints     = rplpoints;
725         code->rplpointcount = count;
726         code->regalloc      = regalloc;
727         code->regalloccount = alloccount;
728         code->globalcount   = 0;
729         code->savedintcount = INT_SAV_CNT - rd->savintreguse;
730         code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
731         code->memuse        = rd->memuse;
732         code->stackframesize = jd->cd->stackframesize;
733
734         REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count);
735         REPLACE_COUNT_INC(stat_regallocs, alloccount);
736
737         /* everything alright */
738
739         return true;
740 }
741
742
743 /* replace_free_replacement_points *********************************************
744  
745    Free memory used by replacement points.
746   
747    IN:
748        code.............codeinfo whose replacement points should be freed.
749   
750 *******************************************************************************/
751
752 void replace_free_replacement_points(codeinfo *code)
753 {
754         assert(code);
755
756         if (code->rplpoints)
757                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
758
759         if (code->regalloc)
760                 MFREE(code->regalloc,rplalloc,code->regalloccount);
761
762         code->rplpoints = NULL;
763         code->rplpointcount = 0;
764         code->regalloc = NULL;
765         code->regalloccount = 0;
766         code->globalcount = 0;
767 }
768
769
770 /* replace_activate_replacement_point ******************************************
771  
772    Activate a replacement point. When this function returns, the
773    replacement point is "armed", that is each thread reaching this point
774    will be replace to `target`.
775    
776    IN:
777        rp...............replacement point to activate
778            target...........target of replacement
779   
780 *******************************************************************************/
781
782 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
783 {
784         assert(rp->target == NULL);
785
786         DOLOG( printf("activate replacement point:\n");
787                    replace_replacement_point_println(rp, 1); fflush(stdout); );
788
789         rp->target = target;
790
791 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
792         md_patch_replacement_point(rp);
793 #endif
794 }
795
796
797 /* replace_deactivate_replacement_point ****************************************
798  
799    Deactivate a replacement point. When this function returns, the
800    replacement point is "un-armed", that is a each thread reaching this point
801    will just continue normally.
802    
803    IN:
804        rp...............replacement point to deactivate
805   
806 *******************************************************************************/
807
808 void replace_deactivate_replacement_point(rplpoint *rp)
809 {
810         assert(rp->target);
811
812         DOLOG( printf("deactivate replacement point:\n");
813                    replace_replacement_point_println(rp, 1); fflush(stdout); );
814
815         rp->target = NULL;
816
817 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
818         md_patch_replacement_point(rp);
819 #endif
820 }
821
822
823 /* replace_read_value **********************************************************
824
825    Read a value with the given allocation from the execution state.
826    
827    IN:
828            es...............execution state
829            sp...............stack pointer of the execution state (XXX eliminate?)
830            ra...............allocation
831            javaval..........where to put the value
832
833    OUT:
834        *javaval.........the value
835   
836 *******************************************************************************/
837
838 static void replace_read_value(executionstate_t *es,
839                                                            stackslot_t *sp,
840                                                            rplalloc *ra,
841                                                            u8 *javaval)
842 {
843         if (ra->flags & INMEMORY) {
844                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
845 #ifdef HAS_4BYTE_STACKSLOT
846                 if (IS_2_WORD_TYPE(ra->type)) {
847                         *javaval = *(u8*)(sp + ra->regoff);
848                 }
849                 else {
850 #endif
851                         *javaval = sp[ra->regoff];
852 #ifdef HAS_4BYTE_STACKSLOT
853                 }
854 #endif
855         }
856         else {
857                 /* allocated register */
858                 if (IS_FLT_DBL_TYPE(ra->type)) {
859                         *javaval = es->fltregs[ra->regoff];
860                 }
861                 else {
862                         *javaval = es->intregs[ra->regoff];
863                 }
864         }
865 }
866
867
868 /* replace_write_value *********************************************************
869
870    Write a value to the given allocation in the execution state.
871    
872    IN:
873            es...............execution state
874            sp...............stack pointer of the execution state (XXX eliminate?)
875            ra...............allocation
876            *javaval.........the value
877
878 *******************************************************************************/
879
880 static void replace_write_value(executionstate_t *es,
881                                                             stackslot_t *sp,
882                                                             rplalloc *ra,
883                                                             u8 *javaval)
884 {
885         if (ra->flags & INMEMORY) {
886                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
887 #ifdef HAS_4BYTE_STACKSLOT
888                 if (IS_2_WORD_TYPE(ra->type)) {
889                         *(u8*)(sp + ra->regoff) = *javaval;
890                 }
891                 else {
892 #endif
893                         sp[ra->regoff] = *javaval;
894 #ifdef HAS_4BYTE_STACKSLOT
895                 }
896 #endif
897         }
898         else {
899                 /* allocated register */
900                 if (IS_FLT_DBL_TYPE(ra->type)) {
901                         es->fltregs[ra->regoff] = *javaval;
902                 }
903                 else {
904                         es->intregs[ra->regoff] = *javaval;
905                 }
906         }
907 }
908
909
910 /* replace_read_executionstate *************************************************
911
912    Read the given executions state and translate it to a source frame.
913    
914    IN:
915        rp...............replacement point at which `es` was taken
916            es...............execution state
917            ss...............where to put the source state
918
919    OUT:
920        *ss..............the source state derived from the execution state
921   
922 *******************************************************************************/
923
924 static s4 replace_normalize_type_map[] = {
925 /* RPLPOINT_TYPE_STD    |--> */ RPLPOINT_TYPE_STD,
926 /* RPLPOINT_TYPE_EXH    |--> */ RPLPOINT_TYPE_STD,
927 /* RPLPOINT_TYPE_SBR    |--> */ RPLPOINT_TYPE_STD,
928 /* RPLPOINT_TYPE_CALL   |--> */ RPLPOINT_TYPE_CALL,
929 /* RPLPOINT_TYPE_INLINE |--> */ RPLPOINT_TYPE_CALL,
930 /* RPLPOINT_TYPE_RETURN |--> */ RPLPOINT_TYPE_RETURN,
931 /* RPLPOINT_TYPE_BODY   |--> */ RPLPOINT_TYPE_STD
932 };
933
934 static void replace_read_executionstate(rplpoint *rp,
935                                                                                 executionstate_t *es,
936                                                                                 sourcestate_t *ss,
937                                                                                 bool topframe)
938 {
939         methodinfo    *m;
940         codeinfo      *code;
941         int            count;
942         int            i;
943         rplalloc      *ra;
944         sourceframe_t *frame;
945         int            topslot;
946         stackslot_t   *sp;
947         stackslot_t   *basesp;
948
949         code = rp->code;
950         m = rp->method;
951         topslot = TOP_IS_NORMAL;
952
953         /* stack pointer */
954
955         sp = (stackslot_t *) es->sp;
956
957         /* in some cases the top stack slot is passed in REG_ITMP1 */
958
959         if (rp->type == BBTYPE_EXH) {
960                 topslot = TOP_IS_IN_ITMP1;
961         }
962
963         /* calculate base stack pointer */
964
965         basesp = sp + code_get_stack_frame_size(code);
966
967         /* create the source frame */
968
969         frame = DNEW(sourceframe_t);
970         frame->down = ss->frames;
971         frame->method = rp->method;
972         frame->id = rp->id;
973         assert(rp->type >= 0 && rp->type < sizeof(replace_normalize_type_map)/sizeof(s4));
974         frame->type = replace_normalize_type_map[rp->type];
975         frame->instance = 0;
976         frame->syncslotcount = 0;
977         frame->syncslots = NULL;
978         frame->readrp = rp;
979
980         ss->frames = frame;
981
982         /* read local variables */
983
984         count = m->maxlocals;
985         frame->javalocalcount = count;
986         frame->javalocals = DMNEW(u8, count);
987         frame->javalocaltype = DMNEW(u1, count);
988
989 #if !defined(NDEBUG)
990         /* mark values as undefined */
991         for (i=0; i<count; ++i) {
992                 frame->javalocals[i] = (u8) 0x00dead0000dead00ULL;
993                 frame->javalocaltype[i] = TYPE_VOID;
994         }
995
996         /* some entries in the intregs array are not meaningful */
997         /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
998         es->intregs[REG_SP   ] = (u8) 0x11dead1111dead11ULL;
999 #ifdef REG_PV
1000         es->intregs[REG_PV   ] = (u8) 0x11dead1111dead11ULL;
1001 #endif
1002 #endif /* !defined(NDEBUG) */
1003
1004         /* read javalocals */
1005
1006         count = rp->regalloccount;
1007         ra = rp->regalloc;
1008
1009         while (count && (i = ra->index) >= 0) {
1010                 assert(i < m->maxlocals);
1011                 frame->javalocaltype[i] = ra->type;
1012                 if (ra->type == TYPE_RET)
1013                         frame->javalocals[i] = ra->regoff;
1014                 else
1015                         replace_read_value(es, sp, ra, frame->javalocals + i);
1016                 ra++;
1017                 count--;
1018         }
1019
1020         /* read instance, if this is the first rplpoint */
1021
1022 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1023         if (topframe && !(rp->method->flags & ACC_STATIC) && rp == code->rplpoints) {
1024                 rplalloc instra;
1025                 methoddesc *md;
1026
1027                 md = rp->method->parseddesc;
1028                 assert(md->params);
1029                 assert(md->paramcount >= 1);
1030                 instra.type = TYPE_ADR;
1031                 instra.regoff = md->params[0].regoff;
1032                 if (md->params[0].inmemory) {
1033                         instra.flags = INMEMORY;
1034                         instra.regoff += (1 + code->stackframesize);
1035                 }
1036                 else {
1037                         instra.flags = 0;
1038                 }
1039                 replace_read_value(es, sp, &instra, &(frame->instance));
1040         }
1041 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1042
1043         /* read stack slots */
1044
1045         frame->javastackdepth = count;
1046         frame->javastack = DMNEW(u8, count);
1047         frame->javastacktype = DMNEW(u1, count);
1048
1049 #if !defined(NDEBUG)
1050         /* mark values as undefined */
1051         for (i=0; i<count; ++i) {
1052                 frame->javastack[i] = (u8) 0x00dead0000dead00ULL;
1053                 frame->javastacktype[i] = TYPE_VOID;
1054         }
1055 #endif /* !defined(NDEBUG) */
1056
1057         i = 0;
1058
1059         /* the first stack slot is special in SBR and EXH blocks */
1060
1061         if (topslot == TOP_IS_ON_STACK) {
1062                 assert(count);
1063
1064                 assert(ra->index == RPLALLOC_STACK);
1065                 frame->javastack[i] = sp[-1];
1066                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1067                 count--;
1068                 i++;
1069                 ra++;
1070         }
1071         else if (topslot == TOP_IS_IN_ITMP1) {
1072                 assert(count);
1073
1074                 assert(ra->index == RPLALLOC_STACK);
1075                 frame->javastack[i] = es->intregs[REG_ITMP1];
1076                 frame->javastacktype[i] = TYPE_ADR; /* XXX RET */
1077                 count--;
1078                 i++;
1079                 ra++;
1080         }
1081         else if (topslot == TOP_IS_VOID) {
1082                 assert(count);
1083
1084                 assert(ra->index == RPLALLOC_STACK);
1085                 frame->javastack[i] = 0;
1086                 frame->javastacktype[i] = TYPE_VOID;
1087                 count--;
1088                 i++;
1089                 ra++;
1090         }
1091
1092         /* read remaining stack slots */
1093
1094         for (; count--; ra++) {
1095                 if (ra->index == RPLALLOC_SYNC) {
1096                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1097
1098                         /* only read synchronization slots when traversing an inline point */
1099
1100                         if (!topframe) {
1101                                 sourceframe_t *calleeframe = frame->down;
1102                                 assert(calleeframe);
1103                                 assert(calleeframe->syncslotcount == 0);
1104                                 assert(calleeframe->syncslots == NULL);
1105
1106                                 calleeframe->syncslotcount = 1;
1107                                 calleeframe->syncslots = DMNEW(u8, 1);
1108                                 replace_read_value(es,sp,ra,calleeframe->syncslots);
1109                         }
1110
1111                         frame->javastackdepth--;
1112                         continue;
1113                 }
1114
1115                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1116
1117                 /* do not read parameters of calls down the call chain */
1118
1119                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1120                         frame->javastackdepth--;
1121                 }
1122                 else {
1123                         if (ra->type == TYPE_RET)
1124                                 frame->javastack[i] = ra->regoff;
1125                         else
1126                                 replace_read_value(es,sp,ra,frame->javastack + i);
1127                         frame->javastacktype[i] = ra->type;
1128                         i++;
1129                 }
1130         }
1131 }
1132
1133
1134 /* replace_write_executionstate ************************************************
1135
1136    Translate the given source state into an execution state.
1137    
1138    IN:
1139        rp...............replacement point for which execution state should be
1140                             creates
1141            es...............where to put the execution state
1142            ss...............the given source state
1143
1144    OUT:
1145        *es..............the execution state derived from the source state
1146   
1147 *******************************************************************************/
1148
1149 static void replace_write_executionstate(rplpoint *rp,
1150                                                                                  executionstate_t *es,
1151                                                                                  sourcestate_t *ss,
1152                                                                                  bool topframe)
1153 {
1154         methodinfo     *m;
1155         codeinfo       *code;
1156         int             count;
1157         int             i;
1158         rplalloc       *ra;
1159         sourceframe_t  *frame;
1160         int             topslot;
1161         stackslot_t    *sp;
1162         stackslot_t    *basesp;
1163
1164         code = rp->code;
1165         m = rp->method;
1166         topslot = TOP_IS_NORMAL;
1167
1168         /* pop a source frame */
1169
1170         frame = ss->frames;
1171         assert(frame);
1172         ss->frames = frame->down;
1173
1174         /* calculate stack pointer */
1175
1176         sp = (stackslot_t *) es->sp;
1177
1178         basesp = sp + code_get_stack_frame_size(code);
1179
1180         /* in some cases the top stack slot is passed in REG_ITMP1 */
1181
1182         if (rp->type == BBTYPE_EXH) {
1183                 topslot = TOP_IS_IN_ITMP1;
1184         }
1185
1186         /* write javalocals */
1187
1188         ra = rp->regalloc;
1189         count = rp->regalloccount;
1190
1191         while (count && (i = ra->index) >= 0) {
1192                 assert(i < m->maxlocals);
1193                 assert(i < frame->javalocalcount);
1194                 assert(ra->type == frame->javalocaltype[i]);
1195                 if (ra->type == TYPE_RET) {
1196                         /* XXX assert that it matches this rplpoint */
1197                 }
1198                 else
1199                         replace_write_value(es, sp, ra, frame->javalocals + i);
1200                 count--;
1201                 ra++;
1202         }
1203
1204         /* write stack slots */
1205
1206         i = 0;
1207
1208         /* the first stack slot is special in SBR and EXH blocks */
1209
1210         if (topslot == TOP_IS_ON_STACK) {
1211                 assert(count);
1212
1213                 assert(ra->index == RPLALLOC_STACK);
1214                 assert(i < frame->javastackdepth);
1215                 assert(frame->javastacktype[i] == TYPE_ADR);
1216                 sp[-1] = frame->javastack[i];
1217                 count--;
1218                 i++;
1219                 ra++;
1220         }
1221         else if (topslot == TOP_IS_IN_ITMP1) {
1222                 assert(count);
1223
1224                 assert(ra->index == RPLALLOC_STACK);
1225                 assert(i < frame->javastackdepth);
1226                 assert(frame->javastacktype[i] == TYPE_ADR);
1227                 es->intregs[REG_ITMP1] = frame->javastack[i];
1228                 count--;
1229                 i++;
1230                 ra++;
1231         }
1232         else if (topslot == TOP_IS_VOID) {
1233                 assert(count);
1234
1235                 assert(ra->index == RPLALLOC_STACK);
1236                 assert(i < frame->javastackdepth);
1237                 assert(frame->javastacktype[i] == TYPE_VOID);
1238                 count--;
1239                 i++;
1240                 ra++;
1241         }
1242
1243         /* write remaining stack slots */
1244
1245         for (; count--; ra++) {
1246                 if (ra->index == RPLALLOC_SYNC) {
1247                         assert(rp->type == RPLPOINT_TYPE_INLINE);
1248
1249                         /* only write synchronization slots when traversing an inline point */
1250
1251                         if (!topframe) {
1252                                 assert(frame->down);
1253                                 assert(frame->down->syncslotcount == 1); /* XXX need to understand more cases */
1254                                 assert(frame->down->syncslots != NULL);
1255
1256                                 replace_write_value(es,sp,ra,frame->down->syncslots);
1257                         }
1258                         continue;
1259                 }
1260
1261                 assert(ra->index == RPLALLOC_STACK || ra->index == RPLALLOC_PARAM);
1262
1263                 /* do not write parameters of calls down the call chain */
1264
1265                 if (!topframe && ra->index == RPLALLOC_PARAM) {
1266                         /* skip it */
1267                 }
1268                 else {
1269                         assert(i < frame->javastackdepth);
1270                         assert(ra->type == frame->javastacktype[i]);
1271                         if (ra->type == TYPE_RET) {
1272                                 /* XXX assert that it matches this rplpoint */
1273                         }
1274                         else {
1275                                 replace_write_value(es,sp,ra,frame->javastack + i);
1276                         }
1277                         i++;
1278                 }
1279         }
1280
1281         /* set new pc */
1282
1283         es->pc = rp->pc;
1284 }
1285
1286
1287 /* replace_pop_activation_record ***********************************************
1288
1289    Peel a stack frame from the execution state.
1290    
1291    *** This function imitates the effects of the method epilog ***
1292    *** and returning from the method call.                     ***
1293
1294    IN:
1295            es...............execution state
1296            frame............source frame, receives synchronization slots
1297
1298    OUT:
1299        *es..............the execution state after popping the stack frame
1300   
1301 *******************************************************************************/
1302
1303 u1* replace_pop_activation_record(executionstate_t *es,
1304                                                                   sourceframe_t *frame)
1305 {
1306         u1 *ra;
1307         u1 *pv;
1308         s4 reg;
1309         s4 i;
1310         s4 count;
1311         codeinfo *code;
1312         stackslot_t *basesp;
1313         stackslot_t *sp;
1314
1315         assert(es->code);
1316         assert(frame);
1317
1318         /* read the return address */
1319
1320         ra = md_stacktrace_get_returnaddress(es->sp,
1321                         SIZE_OF_STACKSLOT * es->code->stackframesize);
1322
1323         DOLOG( printf("return address: %p\n", (void*)ra); );
1324
1325         /* find the new codeinfo */
1326
1327         pv = md_codegen_get_pv_from_pc(ra);
1328
1329         DOLOG( printf("PV = %p\n", (void*) pv); );
1330
1331         if (pv == NULL)
1332                 return NULL;
1333
1334         code = *(codeinfo **)(pv + CodeinfoPointer);
1335
1336         DOLOG( printf("CODE = %p\n", (void*) code); );
1337
1338         if (code == NULL)
1339                 return NULL;
1340
1341         /* calculate the base of the stack frame */
1342
1343         sp = (stackslot_t *) es->sp;
1344         basesp = sp + es->code->stackframesize;
1345
1346         /* read slots used for synchronization */
1347
1348         assert(frame->syncslotcount == 0);
1349         assert(frame->syncslots == NULL);
1350         count = code_get_sync_slot_count(es->code);
1351         frame->syncslotcount = count;
1352         frame->syncslots = DMNEW(u8, count);
1353         for (i=0; i<count; ++i) {
1354                 frame->syncslots[i] = sp[es->code->memuse + i];
1355         }
1356
1357         /* restore saved int registers */
1358
1359         reg = INT_REG_CNT;
1360         for (i=0; i<es->code->savedintcount; ++i) {
1361                 while (nregdescint[--reg] != REG_SAV)
1362                         ;
1363                 es->intregs[reg] = *--basesp;
1364         }
1365
1366         /* restore saved flt registers */
1367
1368         /* XXX align? */
1369         reg = FLT_REG_CNT;
1370         for (i=0; i<es->code->savedfltcount; ++i) {
1371                 while (nregdescfloat[--reg] != REG_SAV)
1372                         ;
1373                 basesp -= STACK_SLOTS_PER_FLOAT;
1374                 es->fltregs[reg] = *(u8*)basesp;
1375         }
1376
1377         /* Set the new pc. Subtract one so we do not hit the replacement point */
1378         /* of the instruction following the call, if there is one.             */
1379
1380         es->pc = ra - 1;
1381
1382         /* adjust the stackpointer */
1383
1384         es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize;
1385         es->sp += SIZE_OF_STACKSLOT; /* skip return address */
1386
1387         es->pv = pv;
1388         es->code = code;
1389
1390 #if !defined(NDEBUG)
1391         /* for debugging */
1392         for (i=0; i<INT_REG_CNT; ++i)
1393                 if (nregdescint[i] != REG_SAV)
1394                         es->intregs[i] = 0x33dead3333dead33ULL;
1395         for (i=0; i<FLT_REG_CNT; ++i)
1396                 if (nregdescfloat[i] != REG_SAV)
1397                         es->fltregs[i] = 0x33dead3333dead33ULL;
1398 #endif /* !defined(NDEBUG) */
1399
1400         return ra;
1401 }
1402
1403
1404 /* replace_patch_future_calls **************************************************
1405
1406    Analyse a call site and depending on the kind of call patch the call, the
1407    virtual function table, or the interface table.
1408
1409    IN:
1410            ra...............return address pointing after the call site
1411            calleeframe......source frame of the callee
1412            calleecode.......the codeinfo of the callee
1413
1414 *******************************************************************************/
1415
1416 void replace_patch_future_calls(u1 *ra, sourceframe_t *calleeframe, codeinfo *calleecode)
1417 {
1418         methodptr *mpp;
1419         bool       atentry;
1420 #if !defined(NDEBUG)
1421         codeinfo  *oldcode;
1422         codeinfo  *newcode;
1423 #endif
1424 #if defined(REPLACE_VERBOSE)
1425         s4         i;
1426         char      *logkind;
1427         int        disas = 0;
1428 #endif
1429
1430         assert(ra);
1431         assert(calleecode);
1432
1433         mpp = NULL;
1434
1435         atentry = (calleeframe->down == NULL)
1436                         && !(calleecode->m->flags & ACC_STATIC)
1437                         && (calleeframe->readrp->id == 0); /* XXX */
1438
1439         DOLOG( printf("bytes at patch position:");
1440                    for (i=0; i<16; ++i)
1441                            printf(" %02x", ra[-16+i]);
1442                    printf("\n"); );
1443
1444         if (ra[-2] == 0xff && ra[-1] == 0xd1
1445                         && ra[-7] == 0xb9)
1446         {
1447                 DOLOG_SHORT( logkind = "static   "; );
1448                 DOLOG( printf("PATCHING static call to "); method_println(calleecode->m); disas = 7; );
1449                 REPLACE_COUNT(stat_staticpatch);
1450                 mpp = (methodptr*)(ra - 6);
1451         }
1452 #if defined(REPLACE_PATCH_DYNAMIC_CALL)
1453         else if (ra[-2] == 0xff && ra[-1] == 0xd2
1454                                 && ra[-8] == 0x8b && ra[-7] == 0x91
1455                                 && atentry)
1456         {
1457                 java_objectheader *obj;
1458                 u1 *table;
1459                 u4 offset;
1460
1461                 DOLOG_SHORT( printf("\tinstance: "); java_value_print(TYPE_ADR, calleeframe->instance);
1462                                          printf("\n"); );
1463
1464                 assert(calleeframe->instance != 0);
1465
1466                 obj = (java_objectheader *) (ptrint) calleeframe->instance;
1467                 table = (u1*) obj->vftbl;
1468                 offset = *(u4*)(ra - 6);
1469
1470                 if (ra[-10] == 0x8b && ra[-9] == 0x08) {
1471                         mpp = (methodptr *) (table + offset);
1472                         DOLOG_SHORT( logkind = "virtual  "; );
1473                         DOLOG( printf("updating virtual call at %p\n", (void*) ra); disas = 8);
1474                 }
1475                 else {
1476                         u4 ioffset = *(u4*)(ra - 12);
1477                         u1 *itable = *(u1**)(table + ioffset);
1478
1479                         assert(ra[-14] == 0x8b && ra[-13] == 0x89);
1480                         mpp = (methodptr *) (itable + offset);
1481                         DOLOG_SHORT( logkind = "interface"; );
1482                         DOLOG( printf("updating interface call at %p\n", (void*) ra); disas = 14);
1483                 }
1484         }
1485 #endif /* defined(REPLACE_PATCH_DYNAMIC_CALL) */
1486
1487         if (mpp == NULL)
1488                 return;
1489
1490         DOLOG(
1491                 u1* u1ptr = ra - disas;
1492                 DISASSINSTR(u1ptr);
1493                 DISASSINSTR(u1ptr);
1494                 if (disas > 8)
1495                         DISASSINSTR(u1ptr);
1496                 fflush(stdout);
1497         );
1498
1499         DOLOG( printf("patch method pointer from: %p to %p\n",
1500                                   (void*) *mpp, (void*)calleecode->entrypoint); );
1501
1502 #if !defined(NDEBUG)
1503         oldcode = *(codeinfo **)((u1*)(*mpp) + CodeinfoPointer);
1504         newcode = *(codeinfo **)((u1*)(calleecode->entrypoint) + CodeinfoPointer);
1505
1506         DOLOG_SHORT( printf("\tpatch %s %p ", logkind, (void*) oldcode->entrypoint);
1507                                  method_println(oldcode->m);
1508                                  printf("\t      with      %p ", (void*) newcode->entrypoint);
1509                                  method_println(newcode->m); );
1510
1511         assert(oldcode->m == newcode->m);
1512 #endif
1513
1514         /* write the new entrypoint */
1515
1516         *mpp = (methodptr) calleecode->entrypoint;
1517 }
1518
1519
1520 /* replace_push_activation_record **********************************************
1521
1522    Push a stack frame onto the execution state.
1523    
1524    *** This function imitates the effects of a call and the ***
1525    *** method prolog of the callee.                         ***
1526
1527    IN:
1528            es...............execution state
1529            rpcall...........the replacement point at the call site
1530            callerframe......source frame of the caller
1531            calleecode.......the codeinfo of the callee
1532            calleeframe......source frame of the callee
1533
1534    OUT:
1535        *es..............the execution state after pushing the stack frame
1536   
1537 *******************************************************************************/
1538
1539 void replace_push_activation_record(executionstate_t *es,
1540                                                                         rplpoint *rpcall,
1541                                                                         sourceframe_t *callerframe,
1542                                                                         codeinfo *calleecode,
1543                                                                         sourceframe_t *calleeframe)
1544 {
1545         s4           reg;
1546         s4           i;
1547         s4           count;
1548         stackslot_t *basesp;
1549         stackslot_t *sp;
1550         u1          *ra;
1551
1552         assert(es);
1553         assert(rpcall && rpcall->type == RPLPOINT_TYPE_CALL);
1554         assert(calleecode);
1555         assert(callerframe);
1556         assert(calleeframe);
1557         assert(calleeframe == callerframe->down);
1558
1559         /* write the return address */
1560
1561         es->sp -= SIZE_OF_STACKSLOT;
1562
1563         ra = rpcall->pc + rpcall->callsize;
1564
1565         DOLOG( printf("writing return address %p to %p\n",
1566                                 (void*) ra, (void*) es->sp); );
1567
1568         *((stackslot_t *)es->sp) = (stackslot_t) ra;
1569
1570         /* we move into a new code unit */
1571
1572         es->code = calleecode;
1573
1574         /* set the new pc XXX not needed */
1575
1576         es->pc = es->code->entrypoint;
1577
1578         /* build the stackframe */
1579
1580         DOLOG( printf("building stackframe of %d words at %p\n",
1581                                 es->code->stackframesize, (void*)es->sp); );
1582
1583         sp = (stackslot_t *) es->sp;
1584         basesp = sp;
1585
1586         sp -= es->code->stackframesize;
1587         es->sp = (u1*) sp;
1588
1589         /* in debug mode, invalidate stack frame first */
1590
1591 #if !defined(NDEBUG)
1592         for (i=0; i<(basesp - sp); ++i) {
1593                 sp[i] = 0xdeaddeadU;
1594         }
1595 #endif
1596
1597         /* save int registers */
1598
1599         reg = INT_REG_CNT;
1600         for (i=0; i<es->code->savedintcount; ++i) {
1601                 while (nregdescint[--reg] != REG_SAV)
1602                         ;
1603                 *--basesp = es->intregs[reg];
1604
1605 #if !defined(NDEBUG)
1606                 es->intregs[reg] = 0x44dead4444dead44ULL;
1607 #endif
1608         }
1609
1610         /* save flt registers */
1611
1612         /* XXX align? */
1613         reg = FLT_REG_CNT;
1614         for (i=0; i<es->code->savedfltcount; ++i) {
1615                 while (nregdescfloat[--reg] != REG_SAV)
1616                         ;
1617                 basesp -= STACK_SLOTS_PER_FLOAT;
1618                 *(u8*)basesp = es->fltregs[reg];
1619
1620 #if !defined(NDEBUG)
1621                 es->fltregs[reg] = 0x44dead4444dead44ULL;
1622 #endif
1623         }
1624
1625         /* write slots used for synchronization */
1626
1627         count = code_get_sync_slot_count(es->code);
1628         assert(count == calleeframe->syncslotcount);
1629         for (i=0; i<count; ++i) {
1630                 sp[es->code->memuse + i] = calleeframe->syncslots[i];
1631         }
1632
1633         /* set the PV */
1634
1635         es->pv = es->code->entrypoint;
1636
1637         /* redirect future invocations */
1638
1639 #if defined(REPLACE_PATCH_ALL)
1640         if (rpcall->type == callerframe->readrp->type)
1641 #else
1642         if (rpcall == callerframe->readrp)
1643 #endif
1644                 replace_patch_future_calls(ra, calleeframe, calleecode);
1645 }
1646
1647
1648 /* replace_find_replacement_point **********************************************
1649
1650    Find the replacement point in the given code corresponding to the
1651    position given in the source frame.
1652    
1653    IN:
1654            code.............the codeinfo in which to search the rplpoint
1655            ss...............the source state defining the position to look for
1656            parent...........parent replacement point to match
1657
1658    RETURN VALUE:
1659        the replacement point
1660   
1661 *******************************************************************************/
1662
1663 rplpoint * replace_find_replacement_point(codeinfo *code,
1664                                                                                   sourcestate_t *ss,
1665                                                                                   rplpoint *parent)
1666 {
1667         sourceframe_t *frame;
1668         methodinfo *m;
1669         rplpoint *rp;
1670         s4        i;
1671         s4        j;
1672         s4        stacki;
1673         rplalloc *ra;
1674
1675         assert(ss);
1676
1677         frame = ss->frames;
1678         assert(frame);
1679
1680         DOLOG( printf("searching replacement point for:\n");
1681                    replace_source_frame_println(frame); );
1682
1683         m = frame->method;
1684
1685         DOLOG( printf("code = %p\n", (void*)code); );
1686
1687         rp = code->rplpoints;
1688         i = code->rplpointcount;
1689         while (i--) {
1690                 if (rp->id == frame->id && rp->method == frame->method
1691                                 && rp->parent == parent
1692                                 && replace_normalize_type_map[rp->type] == frame->type)
1693                 {
1694                         /* check if returnAddresses match */
1695                         /* XXX optimize: only do this if JSRs in method */
1696                         DOLOG( printf("checking match for:");
1697                                    replace_replacement_point_println(rp, 1); fflush(stdout); );
1698                         ra = rp->regalloc;
1699                         stacki = 0;
1700                         for (j = rp->regalloccount; j--; ++ra) {
1701                                 if (ra->type == TYPE_RET) {
1702                                         if (ra->index == RPLALLOC_STACK) {
1703                                                 assert(stacki < frame->javastackdepth);
1704                                                 if (frame->javastack[stacki] != ra->regoff)
1705                                                         goto no_match;
1706                                                 stacki++;
1707                                         }
1708                                         else {
1709                                                 assert(ra->index >= 0 && ra->index < frame->javalocalcount);
1710                                                 if (frame->javalocals[ra->index] != ra->regoff)
1711                                                         goto no_match;
1712                                         }
1713                                 }
1714                         }
1715
1716                         /* found */
1717                         return rp;
1718                 }
1719 no_match:
1720                 rp++;
1721         }
1722
1723 #if !defined(NDEBUG)
1724         printf("candidate replacement points were:\n");
1725         rp = code->rplpoints;
1726         i = code->rplpointcount;
1727         for (; i--; ++rp) {
1728                 replace_replacement_point_println(rp, 1);
1729         }
1730 #endif
1731
1732         vm_abort("no matching replacement point found");
1733         return NULL; /* NOT REACHED */
1734 }
1735
1736
1737 /* replace_me ******************************************************************
1738  
1739    This function is called by asm_replacement_out when a thread reaches
1740    a replacement point. `replace_me` must map the execution state to the
1741    target replacement point and let execution continue there.
1742
1743    This function never returns!
1744   
1745    IN:
1746        rp...............replacement point that has been reached
1747            es...............execution state read by asm_replacement_out
1748   
1749 *******************************************************************************/
1750
1751 void replace_me(rplpoint *rp, executionstate_t *es)
1752 {
1753         sourcestate_t  ss;
1754         s4             dumpsize;
1755         rplpoint      *candidate;
1756         codeinfo      *code;
1757         s4             i;
1758         s4             depth;
1759         rplpoint      *origrp;
1760         rplpoint      *parent;
1761         u1            *ra;
1762         sourceframe_t *prevframe;
1763 #if defined(REPLACE_STATISTICS)
1764         codeinfo      *oldcode;
1765 #endif
1766
1767         origrp = rp;
1768         es->code = rp->code;
1769
1770         DOLOG_SHORT( printf("REPLACING(%d %p): (id %d %p) ",
1771                                  stat_replacements, (void*)THREADOBJECT,
1772                                  rp->id, (void*)rp);
1773                                  method_println(es->code->m); );
1774
1775         DOLOG( printf("replace_me(%p,%p)\n",(void*)rp,(void*)es); fflush(stdout);
1776                    replace_replacement_point_println(rp, 1);
1777                    replace_executionstate_println(es); );
1778
1779         REPLACE_COUNT(stat_replacements);
1780
1781         /* mark start of dump memory area */
1782
1783         dumpsize = dump_size();
1784
1785         /* read execution state of old code */
1786
1787         ss.frames = NULL;
1788
1789         /* XXX testing */
1790
1791         depth = 0;
1792         candidate = rp;
1793         do {
1794                 DOLOG( printf("recovering source state for%s:\n",
1795                                         (ss.frames == NULL) ? " TOPFRAME" : "");
1796                            replace_replacement_point_println(candidate, 1); );
1797
1798                 replace_read_executionstate(candidate, es, &ss, ss.frames == NULL);
1799                 REPLACE_COUNT(stat_frames);
1800                 depth++;
1801
1802 #if defined(REPLACE_STATISTICS)
1803                 {
1804                 int adr = 0; int ret = 0; int prim = 0; int vd = 0; int n = 0;
1805                 for (i=0; i<ss.frames->javalocalcount; ++i) {
1806                         switch (ss.frames->javalocaltype[i]) {
1807                                 case TYPE_ADR: adr++; break;
1808                                 case TYPE_RET: ret++; break;
1809                                 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
1810                                 case TYPE_VOID: vd++; break;
1811                                 default: assert(0);
1812                         }
1813                         n++;
1814                 }
1815                 REPLACE_COUNT_DIST(stat_dist_locals, n);
1816                 REPLACE_COUNT_DIST(stat_dist_locals_adr, adr);
1817                 REPLACE_COUNT_DIST(stat_dist_locals_void, vd);
1818                 REPLACE_COUNT_DIST(stat_dist_locals_ret, ret);
1819                 REPLACE_COUNT_DIST(stat_dist_locals_prim, prim);
1820                 adr = ret = prim = n = 0;
1821                 for (i=0; i<ss.frames->javastackdepth; ++i) {
1822                         switch (ss.frames->javastacktype[i]) {
1823                                 case TYPE_ADR: adr++; break;
1824                                 case TYPE_RET: ret++; break;
1825                                 case TYPE_INT: case TYPE_LNG: case TYPE_FLT: case TYPE_DBL: prim++; break;
1826                         }
1827                         n++;
1828                 }
1829                 REPLACE_COUNT_DIST(stat_dist_stack, n);
1830                 REPLACE_COUNT_DIST(stat_dist_stack_adr, adr);
1831                 REPLACE_COUNT_DIST(stat_dist_stack_ret, ret);
1832                 REPLACE_COUNT_DIST(stat_dist_stack_prim, prim);
1833                 }
1834 #endif /* defined(REPLACE_STATISTICS) */
1835
1836                 if (candidate->parent) {
1837                         DOLOG( printf("INLINED!\n"); );
1838                         candidate = candidate->parent;
1839                         assert(candidate->type == RPLPOINT_TYPE_INLINE);
1840                         REPLACE_COUNT(stat_unroll_inline);
1841                 }
1842                 else {
1843                         DOLOG( printf("UNWIND\n"); );
1844                         REPLACE_COUNT(stat_unroll_call);
1845                         code = es->code;
1846                         ra = replace_pop_activation_record(es, ss.frames);
1847                         if (ra == NULL) {
1848                                 DOLOG( printf("BREAKING\n"); );
1849                                 break;
1850                         }
1851                         DOLOG( replace_executionstate_println(es); );
1852                         candidate = NULL;
1853                         rp = es->code->rplpoints;
1854                         for (i=0; i<es->code->rplpointcount; ++i, ++rp)
1855                                 if (rp->pc <= es->pc)
1856                                         candidate = rp;
1857                         if (!candidate)
1858                                 DOLOG( printf("NO CANDIDATE!\n"); );
1859                         else {
1860                                 DOLOG( printf("found replacement point.\n");
1861                                            replace_replacement_point_println(candidate, 1); );
1862                                 assert(candidate->type == RPLPOINT_TYPE_CALL);
1863                         }
1864                 }
1865         } while (candidate);
1866
1867         REPLACE_COUNT_DIST(stat_dist_frames, depth);
1868         DOLOG( replace_sourcestate_println(&ss); );
1869
1870         /* write execution state of new code */
1871
1872         DOLOG( replace_executionstate_println(es); );
1873
1874         code = es->code;
1875
1876         /* XXX get new code */
1877
1878         parent = NULL;
1879
1880         while (ss.frames) {
1881
1882                 candidate = replace_find_replacement_point(code, &ss, parent);
1883
1884                 DOLOG( printf("creating execution state for%s:\n",
1885                                 (ss.frames->down == NULL) ? " TOPFRAME" : "");
1886                            replace_replacement_point_println(ss.frames->readrp, 1);
1887                            replace_replacement_point_println(candidate, 1); );
1888
1889                 DOLOG_SHORT( printf("\t%c%s ",
1890                                          (candidate == ss.frames->readrp) ? '=' : '+',
1891                                          replace_type_str[candidate->type]); 
1892                                      method_println(ss.frames->method); );
1893
1894                 prevframe = ss.frames;
1895                 replace_write_executionstate(candidate, es, &ss, ss.frames->down == NULL);
1896                 if (ss.frames == NULL)
1897                         break;
1898                 DOLOG( replace_executionstate_println(es); );
1899
1900                 if (candidate->type == RPLPOINT_TYPE_CALL) {
1901 #if defined(REPLACE_STATISTICS)
1902                         oldcode = ss.frames->method->code;
1903 #endif
1904                         code = jit_get_current_code(ss.frames->method);
1905
1906                         REPLACE_COUNT_IF(stat_recompile, code != oldcode);
1907
1908                         DOLOG( printf("pushing activation record for:\n");
1909                                    replace_replacement_point_println(candidate, 1); );
1910
1911                         replace_push_activation_record(es, candidate, prevframe, code, ss.frames);
1912                         parent = NULL;
1913                 }
1914                 else {
1915                         parent = candidate;
1916                 }
1917                 DOLOG( replace_executionstate_println(es); );
1918         }
1919
1920         DOLOG( replace_executionstate_println(es); );
1921
1922         assert(candidate);
1923         if (candidate == origrp) {
1924                 DOLOG_SHORT(
1925                         printf("WARNING: identity replacement, turning off rp to avoid infinite loop\n");
1926                 );
1927                 replace_deactivate_replacement_point(origrp);
1928         }
1929
1930         /* release dump area */
1931
1932         dump_release(dumpsize);
1933
1934         /* enter new code */
1935
1936         DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
1937
1938 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
1939         asm_replacement_in(es);
1940 #endif
1941         abort(); /* NOT REACHED */
1942 }
1943
1944
1945 /* replace_replacement_point_println *******************************************
1946  
1947    Print replacement point info.
1948   
1949    IN:
1950        rp...............the replacement point to print
1951   
1952 *******************************************************************************/
1953
1954 #if !defined(NDEBUG)
1955
1956 #define TYPECHAR(t)  (((t) >= 0 && (t) <= TYPE_RET) ? show_jit_type_letters[t] : '?')
1957
1958 void replace_replacement_point_println(rplpoint *rp, int depth)
1959 {
1960         int j;
1961         int index;
1962
1963         if (!rp) {
1964                 printf("(rplpoint *)NULL\n");
1965                 return;
1966         }
1967
1968         for (j=0; j<depth; ++j)
1969                 putchar('\t');
1970
1971         printf("rplpoint (id %d) %p pc:%p+%d out:%p target:%p mcode:%016llx type:%s",
1972                         rp->id, (void*)rp,rp->pc,rp->callsize,rp->outcode,(void*)rp->target,
1973                         (unsigned long long)rp->mcode,replace_type_str[rp->type]);
1974         if (rp->flags & RPLPOINT_FLAG_NOTRAP)
1975                 printf(" NOTRAP");
1976         printf(" parent:%p\n", (void*)rp->parent);
1977         for (j=0; j<depth; ++j)
1978                 putchar('\t');
1979         printf("ra:%d = [",     rp->regalloccount);
1980
1981         for (j=0; j<rp->regalloccount; ++j) {
1982                 if (j)
1983                         putchar(' ');
1984                 index = rp->regalloc[j].index;
1985                 switch (index) {
1986                         case RPLALLOC_STACK: printf("S"); break;
1987                         case RPLALLOC_PARAM: printf("P"); break;
1988                         case RPLALLOC_SYNC : printf("Y"); break;
1989                         default: printf("%d", index);
1990                 }
1991                 printf(":%1c:", TYPECHAR(rp->regalloc[j].type));
1992                 if (rp->regalloc[j].type == TYPE_RET) {
1993                         printf("ret(L%03d)", rp->regalloc[j].regoff);
1994                 }
1995                 else {
1996                         show_allocation(rp->regalloc[j].type, rp->regalloc[j].flags, rp->regalloc[j].regoff);
1997                 }
1998         }
1999
2000         printf("]\n");
2001         for (j=0; j<depth; ++j)
2002                 putchar('\t');
2003         printf("method: ");
2004         method_print(rp->method);
2005
2006         printf("\n");
2007 }
2008 #endif
2009
2010
2011 /* replace_show_replacement_points *********************************************
2012  
2013    Print replacement point info.
2014   
2015    IN:
2016        code.............codeinfo whose replacement points should be printed.
2017   
2018 *******************************************************************************/
2019
2020 #if !defined(NDEBUG)
2021 void replace_show_replacement_points(codeinfo *code)
2022 {
2023         int i;
2024         int depth;
2025         rplpoint *rp;
2026         rplpoint *parent;
2027
2028         if (!code) {
2029                 printf("(codeinfo *)NULL\n");
2030                 return;
2031         }
2032
2033         printf("\treplacement points: %d\n",code->rplpointcount);
2034
2035         printf("\ttotal allocations : %d\n",code->regalloccount);
2036         printf("\tsaved int regs    : %d\n",code->savedintcount);
2037         printf("\tsaved flt regs    : %d\n",code->savedfltcount);
2038         printf("\tmemuse            : %d\n",code->memuse);
2039
2040         printf("\n");
2041
2042         for (i=0; i<code->rplpointcount; ++i) {
2043                 rp = code->rplpoints + i;
2044
2045                 assert(rp->code == code);
2046
2047                 depth = 1;
2048                 parent = rp->parent;
2049                 while (parent) {
2050                         depth++;
2051                         parent = parent->parent;
2052                 }
2053                 replace_replacement_point_println(rp, depth);
2054         }
2055 }
2056 #endif
2057
2058
2059 /* replace_executionstate_println **********************************************
2060  
2061    Print execution state
2062   
2063    IN:
2064        es...............the execution state to print
2065   
2066 *******************************************************************************/
2067
2068 #if !defined(NDEBUG)
2069 void replace_executionstate_println(executionstate_t *es)
2070 {
2071         int i;
2072         int slots;
2073         stackslot_t *sp;
2074         int extraslots;
2075         
2076         if (!es) {
2077                 printf("(executionstate_t *)NULL\n");
2078                 return;
2079         }
2080
2081         printf("executionstate_t:\n");
2082         printf("\tpc = %p",(void*)es->pc);
2083         printf("  sp = %p",(void*)es->sp);
2084         printf("  pv = %p\n",(void*)es->pv);
2085 #if defined(ENABLE_DISASSEMBLER)
2086         for (i=0; i<INT_REG_CNT; ++i) {
2087                 if (i%4 == 0)
2088                         printf("\t");
2089                 else
2090                         printf(" ");
2091                 printf("%-3s = %016llx",regs[i],(unsigned long long)es->intregs[i]);
2092                 if (i%4 == 3)
2093                         printf("\n");
2094         }
2095         for (i=0; i<FLT_REG_CNT; ++i) {
2096                 if (i%4 == 0)
2097                         printf("\t");
2098                 else
2099                         printf(" ");
2100                 printf("F%02d = %016llx",i,(unsigned long long)es->fltregs[i]);
2101                 if (i%4 == 3)
2102                         printf("\n");
2103         }
2104 #endif
2105
2106         sp = (stackslot_t *) es->sp;
2107
2108         extraslots = 2;
2109
2110         if (es->code) {
2111                 methoddesc *md = es->code->m->parseddesc;
2112                 slots = code_get_stack_frame_size(es->code);
2113                 extraslots = 1 + md->memuse;
2114         }
2115         else
2116                 slots = 0;
2117
2118
2119         if (slots) {
2120                 printf("\tstack slots(+%d) at sp:", extraslots);
2121                 for (i=0; i<slots+extraslots; ++i) {
2122                         if (i%4 == 0)
2123                                 printf("\n\t\t");
2124                         printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
2125 #ifdef HAS_4BYTE_STACKSLOT
2126                         printf("%08lx",(unsigned long)*sp++);
2127 #else
2128                         printf("%016llx",(unsigned long long)*sp++);
2129 #endif
2130                         printf("%c", (i >= slots) ? ')' : ' ');
2131                 }
2132                 printf("\n");
2133         }
2134
2135         printf("\tcode: %p", (void*)es->code);
2136         if (es->code != NULL) {
2137                 printf(" stackframesize=%d ", es->code->stackframesize);
2138                 method_print(es->code->m);
2139         }
2140         printf("\n");
2141
2142         printf("\n");
2143 }
2144 #endif
2145
2146 #if !defined(NDEBUG)
2147 void java_value_print(s4 type, u8 value)
2148 {
2149         java_objectheader *obj;
2150         utf               *u;
2151
2152         printf("%016llx",(unsigned long long) value);
2153
2154         if (type < 0 || type > TYPE_RET)
2155                 printf(" <INVALID TYPE:%d>", type);
2156         else
2157                 printf(" %s", show_jit_type_names[type]);
2158
2159         if (type == TYPE_ADR && value != 0) {
2160                 obj = (java_objectheader *) (ptrint) value;
2161                 putchar(' ');
2162                 utf_display_printable_ascii_classname(obj->vftbl->class->name);
2163
2164                 if (obj->vftbl->class == class_java_lang_String) {
2165                         printf(" \"");
2166                         u = javastring_toutf((java_lang_String *)obj, false);
2167                         utf_display_printable_ascii(u);
2168                         printf("\"");
2169                 }
2170         }
2171         else if (type == TYPE_INT || type == TYPE_LNG) {
2172                 printf(" %lld", (long long) value);
2173         }
2174 }
2175 #endif /* !defined(NDEBUG) */
2176
2177
2178 #if !defined(NDEBUG)
2179 void replace_source_frame_println(sourceframe_t *frame)
2180 {
2181         s4 i;
2182         s4 t;
2183
2184         printf("\t");
2185         method_println(frame->method);
2186         printf("\tid: %d\n", frame->id);
2187         printf("\ttype: %s\n", replace_type_str[frame->type]);
2188         printf("\n");
2189
2190         if (frame->instance) {
2191                 printf("\tinstance: ");
2192                 java_value_print(TYPE_ADR, frame->instance);
2193                 printf("\n");
2194         }
2195
2196         if (frame->javalocalcount) {
2197                 printf("\tlocals (%d):\n",frame->javalocalcount);
2198                 for (i=0; i<frame->javalocalcount; ++i) {
2199                         t = frame->javalocaltype[i];
2200                         if (t == TYPE_VOID) {
2201                                 printf("\tlocal[ %2d] = void\n",i);
2202                         }
2203                         else {
2204                                 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
2205                                 java_value_print(t, frame->javalocals[i]);
2206                                 printf("\n");
2207                         }
2208                 }
2209                 printf("\n");
2210         }
2211
2212         if (frame->javastackdepth) {
2213                 printf("\tstack (depth %d):\n",frame->javastackdepth);
2214                 for (i=0; i<frame->javastackdepth; ++i) {
2215                         t = frame->javastacktype[i];
2216                         if (t == TYPE_VOID) {
2217                                 printf("\tstack[%2d] = void", i);
2218                         }
2219                         else {
2220                                 printf("\tstack[%2d] = ",i);
2221                                 java_value_print(frame->javastacktype[i], frame->javastack[i]);
2222                                 printf("\n");
2223                         }
2224                 }
2225                 printf("\n");
2226         }
2227
2228         if (frame->syncslotcount) {
2229                 printf("\tsynchronization slots (%d):\n",frame->syncslotcount);
2230                 for (i=0; i<frame->syncslotcount; ++i) {
2231                         printf("\tslot[%2d] = ",i);
2232 #ifdef HAS_4BYTE_STACKSLOT
2233                         printf("%08lx\n",(unsigned long) frame->syncslots[i]);
2234 #else
2235                         printf("%016llx\n",(unsigned long long) frame->syncslots[i]);
2236 #endif
2237                 }
2238                 printf("\n");
2239         }
2240
2241         if (frame->readrp) {
2242                 printf("\tread replacement point:\n");
2243                 replace_replacement_point_println(frame->readrp, 2);
2244                 printf("\n");
2245         }
2246 }
2247 #endif /* !defined(NDEBUG) */
2248
2249
2250 /* replace_sourcestate_println *************************************************
2251  
2252    Print source state
2253   
2254    IN:
2255        ss...............the source state to print
2256   
2257 *******************************************************************************/
2258
2259 #if !defined(NDEBUG)
2260 void replace_sourcestate_println(sourcestate_t *ss)
2261 {
2262         int i;
2263         sourceframe_t *frame;
2264
2265         if (!ss) {
2266                 printf("(sourcestate_t *)NULL\n");
2267                 return;
2268         }
2269
2270         printf("sourcestate_t:\n");
2271
2272         for (i=0, frame = ss->frames; frame != NULL; frame = frame->down, ++i) {
2273                 printf("    frame %d:\n", i);
2274                 replace_source_frame_println(frame);
2275         }
2276 }
2277 #endif
2278
2279 /*
2280  * These are local overrides for various environment variables in Emacs.
2281  * Please do not remove this and leave it at the end of the file, where
2282  * Emacs will automagically detect them.
2283  * ---------------------------------------------------------------------
2284  * Local variables:
2285  * mode: c
2286  * indent-tabs-mode: t
2287  * c-basic-offset: 4
2288  * tab-width: 4
2289  * End:
2290  * vim:noexpandtab:sw=4:ts=4:
2291  */