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