* src/vm/jit/code.c (code_get_stack_frame_size): Implement stack alignment
[cacao.git] / src / vm / jit / replace.c
1 /* vm/jit/replace.c - on-stack replacement of methods
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Edwin Steiner
28
29    Changes:
30
31    $Id$
32
33 */
34
35 #include "config.h"
36 #include "vm/types.h"
37
38 #include <assert.h>
39 #include <stdlib.h>
40
41 #include "mm/memory.h"
42 #include "toolbox/logging.h"
43 #include "vm/options.h"
44 #include "vm/jit/jit.h"
45 #include "vm/jit/replace.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/disass.h"
48 #include "arch.h"
49
50 /*** constants used internally ************************************************/
51
52 #define TOP_IS_NORMAL    0
53 #define TOP_IS_ON_STACK  1
54 #define TOP_IS_IN_ITMP1  2
55
56 /* replace_create_replacement_points *******************************************
57  
58    Create the replacement points for the given code.
59   
60    IN:
61        code.............codeinfo where replacement points should be stored
62                             code->rplpoints must be NULL.
63                                                 code->rplpointcount must be 0.
64            rd...............registerdata containing allocation info.
65   
66    OUT:
67        code->rplpoints.......set to the list of replacement points
68            code->rplpointcount...number of replacement points
69            code->regalloc........list of allocation info
70            code->regalloccount...total length of allocation info list
71            code->globalcount.....number of global allocations at the
72                                  start of code->regalloc
73   
74    RETURN VALUE:
75        true.............everything ok 
76        false............an exception has been thrown
77    
78 *******************************************************************************/
79
80 bool replace_create_replacement_points(codeinfo *code,registerdata *rd)
81 {
82         basicblock *bptr;
83         int count;
84         methodinfo *m;
85         rplpoint *rplpoints;
86         rplpoint *rp;
87         int alloccount;
88         int globalcount;
89         rplalloc *regalloc;
90         rplalloc *ra;
91         int i;
92         int t;
93         stackptr sp;
94         bool indexused;
95
96         /* assert that we wont overwrite already allocated data */
97         
98         assert(code);
99         assert(code->m);
100         assert(code->rplpoints == NULL);
101         assert(code->rplpointcount == 0);
102         assert(code->regalloc == NULL);
103         assert(code->regalloccount == 0);
104         assert(code->globalcount == 0);
105
106         /* iterate over the basic block list to find replacement points */
107
108         m = code->m;
109
110         count = 0;
111         alloccount = 0;
112         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
113                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
114                         continue;
115
116                 /* there will be a replacement point at the start of this block */
117                 
118                 count++;
119                 alloccount += bptr->indepth;
120         }
121
122         /* if no points were found, there's nothing to do */
123         
124         if (!count)
125                 return true;
126
127         /* count global register allocations */
128
129         globalcount = 0;
130
131         for (i=0; i<m->maxlocals; ++i) {
132                 indexused = false;
133                 for (t=0; t<5; ++t) {
134 #if defined(ENABLE_INTRP)
135                         if (!opt_intrp) {
136 #endif
137                                 if (rd->locals[i][t].type == t) {
138                                         globalcount++;
139                                         indexused = true;
140                                 }
141 #if defined(ENABLE_INTRP)
142                         }
143 #endif
144                 }
145                 if (!indexused)
146                         globalcount++; /* dummy rplalloc */
147         }
148
149         alloccount += globalcount;
150
151         /* allocate replacement point array and allocation array */
152         
153         rplpoints = MNEW(rplpoint,count);
154         regalloc = MNEW(rplalloc,alloccount);
155         ra = regalloc;
156
157         /* store global register allocations */
158
159         for (i=0; i<m->maxlocals; ++i) {
160                 indexused = false;
161                 for (t=0; t<5; ++t) {
162 #if defined(ENABLE_INTRP)
163                         if (!opt_intrp) {
164 #endif
165                                 if (rd->locals[i][t].type == t) {
166                                         ra->flags = rd->locals[i][t].flags & (INMEMORY);
167                                         ra->index = rd->locals[i][t].regoff;
168                                         ra->type  = t;
169                                         ra->next = (indexused) ? 0 : 1;
170                                         ra++;
171                                         indexused = true;
172                                 }
173 #if defined(ENABLE_INTRP)
174                         }
175 #endif
176                 }
177                 if (!indexused) {
178                         /* dummy rplalloc */
179                         ra->type = -1;
180                         ra->flags = 0;
181                         ra->index = 0;
182                         ra->next = 1;
183                         ra++;
184                 }
185         }
186
187         /* initialize replacement point structs */
188
189         rp = rplpoints;
190         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
191                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
192                         continue;
193
194                 /* there will be a replacement point at the start of this block */
195
196                 rp->pc = NULL;        /* set by codegen */
197                 rp->outcode = NULL;   /* set by codegen */
198                 rp->code = code;
199                 rp->target = NULL;
200                 rp->regalloc = ra;
201                 rp->flags = 0;
202                 rp->type = bptr->type;
203
204                 /* store local allocation info */
205
206                 for (sp = bptr->instack; sp; sp = sp->prev) {
207                         ra->flags = sp->flags & (INMEMORY);
208                         ra->index = sp->regoff;
209                         ra->type  = sp->type;
210                         ra->next  = 1;
211                         ra++;
212                 }
213
214                 rp->regalloccount = ra - rp->regalloc;
215                 
216                 rp++;
217         }
218
219         /* store the data in the codeinfo */
220
221         code->rplpoints = rplpoints;
222         code->rplpointcount = count;
223         code->regalloc = regalloc;
224         code->regalloccount = alloccount;
225         code->globalcount = globalcount;
226         code->savedintcount = INT_SAV_CNT - rd->savintreguse;
227         code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
228         code->memuse = rd->memuse;
229         code->isleafmethod = m->isleafmethod; /* XXX will be moved to codeinfo */
230
231         /* everything alright */
232
233         return true;
234 }
235
236 /* replace_free_replacement_points *********************************************
237  
238    Free memory used by replacement points.
239   
240    IN:
241        code.............codeinfo whose replacement points should be freed.
242   
243 *******************************************************************************/
244
245 void replace_free_replacement_points(codeinfo *code)
246 {
247         assert(code);
248
249         if (code->rplpoints)
250                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
251
252         if (code->regalloc)
253                 MFREE(code->regalloc,rplalloc,code->regalloccount);
254
255         code->rplpoints = NULL;
256         code->rplpointcount = 0;
257         code->regalloc = NULL;
258         code->regalloccount = 0;
259         code->globalcount = 0;
260 }
261
262 /* replace_activate_replacement_point ******************************************
263  
264    Activate a replacement point. When this function returns, the
265    replacement point is "armed", that is each thread reaching this point
266    will be replace to `target`.
267    
268    IN:
269        rp...............replacement point to activate
270            target...........target of replacement
271   
272 *******************************************************************************/
273
274 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
275 {
276         assert(rp->target == NULL);
277         
278 #ifndef NDEBUG
279         printf("activate replacement point: ");
280         replace_replacement_point_println(rp);
281         fflush(stdout);
282 #endif
283         
284         rp->target = target;
285         
286 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
287         md_patch_replacement_point(rp);
288 #endif
289 }
290
291 /* replace_deactivate_replacement_point ****************************************
292  
293    Deactivate a replacement point. When this function returns, the
294    replacement point is "un-armed", that is a each thread reaching this point
295    will just continue normally.
296    
297    IN:
298        rp...............replacement point to deactivate
299   
300 *******************************************************************************/
301
302 void replace_deactivate_replacement_point(rplpoint *rp)
303 {
304         assert(rp->target);
305         
306 #ifndef NDEBUG
307         printf("deactivate replacement point: ");
308         replace_replacement_point_println(rp);
309         fflush(stdout);
310 #endif
311         
312         rp->target = NULL;
313         
314 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
315         md_patch_replacement_point(rp);
316 #endif
317 }
318
319 /* replace_read_executionstate *************************************************
320
321    Read the given executions state and translate it to a source state.
322    
323    IN:
324        rp...............replacement point at which `es` was taken
325            es...............execution state
326            ss...............where to put the source state
327
328    OUT:
329        *ss..............the source state derived from the execution state
330   
331 *******************************************************************************/
332
333 inline static void replace_read_value(executionstate *es,
334 #ifdef HAS_4BYTE_STACKSLOT
335                                                                           u4 *sp,
336 #else
337                                                                           u8 *sp,
338 #endif
339                                                                           rplalloc *ra,
340                                                                           u8 *javaval)
341 {
342         if (ra->flags & INMEMORY) {
343                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
344 #ifdef HAS_4BYTE_STACKSLOT
345                 if (IS_2_WORD_TYPE(ra->type)) {
346                         *javaval = *(u8*)(sp + ra->index);
347                 }
348                 else {
349 #endif
350                         *javaval = sp[ra->index];
351 #ifdef HAS_4BYTE_STACKSLOT
352                 }
353 #endif
354         }
355         else {
356                 /* allocated register */
357                 if (IS_FLT_DBL_TYPE(ra->type)) {
358                         *javaval = es->fltregs[ra->index];
359                 }
360                 else {
361                         *javaval = es->intregs[ra->index];
362                 }
363         }
364 }
365
366 inline static void replace_write_value(executionstate *es,
367 #ifdef HAS_4BYTE_STACKSLOT
368                                                                           u4 *sp,
369 #else
370                                                                           u8 *sp,
371 #endif
372                                                                           rplalloc *ra,
373                                                                           u8 *javaval)
374 {
375         if (ra->flags & INMEMORY) {
376                 /* XXX HAS_4BYTE_STACKSLOT may not be the right discriminant here */
377 #ifdef HAS_4BYTE_STACKSLOT
378                 if (IS_2_WORD_TYPE(ra->type)) {
379                         *(u8*)(sp + ra->index) = *javaval;
380                 }
381                 else {
382 #endif
383                         sp[ra->index] = *javaval;
384 #ifdef HAS_4BYTE_STACKSLOT
385                 }
386 #endif
387         }
388         else {
389                 /* allocated register */
390                 if (IS_FLT_DBL_TYPE(ra->type)) {
391                         es->fltregs[ra->index] = *javaval;
392                 }
393                 else {
394                         es->intregs[ra->index] = *javaval;
395                 }
396         }
397 }
398
399 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
400                                                                          sourcestate *ss)
401 {
402         methodinfo *m;
403         codeinfo *code;
404         int count;
405         int i;
406         int t;
407         int allocs;
408         rplalloc *ra;
409         methoddesc *md;
410         int topslot;
411 #ifdef HAS_4BYTE_STACKSLOT
412         u4 *sp;
413         u4 *basesp;
414 #else
415         u8 *sp;
416         u8 *basesp;
417 #endif
418
419         code = rp->code;
420         m = code->m;
421         md = m->parseddesc;
422         topslot = TOP_IS_NORMAL;
423
424         /* stack pointers */
425
426 #ifdef HAS_4BYTE_STACKSLOT
427         sp = (u4*) es->sp;
428 #else
429         sp = (u8*) es->sp;
430 #endif
431
432         /* on some architectures the returnAddress is passed on the stack by JSR */
433
434 #if defined(__I386__) || defined(__X86_64__)
435         if (rp->type == BBTYPE_SBR) {
436                 sp++;
437                 topslot = TOP_IS_ON_STACK;
438         }
439 #endif
440
441         /* in some cases the top stack slot is passed in REG_ITMP1 */
442
443         if (  (rp->type == BBTYPE_EXH)
444 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
445            || (rp->type == BBTYPE_SBR)
446 #endif
447            )
448         {
449                 topslot = TOP_IS_IN_ITMP1;
450         }
451
452         /* calculate base stack pointer */
453         
454         basesp = sp + code_get_stack_frame_size(code);
455
456         ss->stackbase = (u1*) basesp;
457
458         /* read local variables */
459
460         count = m->maxlocals;
461         ss->javalocalcount = count;
462         ss->javalocals = DMNEW(u8,count * 5);
463
464 #ifndef NDEBUG
465         /* mark values as undefined */
466         for (i=0; i<count*5; ++i)
467                 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
468
469         /* some entries in the intregs array are not meaningful */
470         /*es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;*/
471         es->intregs[REG_SP   ] = (u8) 0x11dead1111dead11ULL;
472 #ifdef REG_PV
473         es->intregs[REG_PV   ] = (u8) 0x11dead1111dead11ULL;
474 #endif
475 #endif /* NDEBUG */
476         
477         ra = code->regalloc;
478
479         i = -1;
480         for (allocs = code->globalcount; allocs--; ra++) {
481                 if (ra->next)
482                         i++;
483                 t = ra->type;
484                 if (t == -1)
485                         continue; /* dummy rplalloc */
486
487                 replace_read_value(es,sp,ra,ss->javalocals + (5*i+t));
488         }
489
490         /* read stack slots */
491
492         count = rp->regalloccount;
493         ss->javastackdepth = count;
494         ss->javastack = DMNEW(u8,count);
495
496 #ifndef NDEBUG
497         /* mark values as undefined */
498         for (i=0; i<count; ++i)
499                 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
500 #endif
501         
502         i = 0;
503         ra = rp->regalloc;
504
505         /* the first stack slot is special in SBR and EXH blocks */
506
507         if (topslot == TOP_IS_ON_STACK) {
508                 assert(count);
509                 
510                 ss->javastack[i] = sp[-1];
511                 count--;
512                 i++;
513                 ra++;
514         }
515         else if (topslot == TOP_IS_IN_ITMP1) {
516                 assert(count);
517
518                 ss->javastack[i] = es->intregs[REG_ITMP1];
519                 count--;
520                 i++;
521                 ra++;
522         }
523         
524         /* read remaining stack slots */
525         
526         for (; count--; ra++, i++) {
527                 assert(ra->next);
528
529                 replace_read_value(es,sp,ra,ss->javastack + i);
530         }
531
532         /* read unused callee saved int regs */
533         
534         count = INT_SAV_CNT;
535         for (i=0; count > code->savedintcount; ++i) {
536                 assert(i < INT_REG_CNT);
537                 if (nregdescint[i] == REG_SAV)
538                         ss->savedintregs[--count] = es->intregs[i];
539         }
540
541         /* read saved int regs */
542
543         for (i=0; i<code->savedintcount; ++i) {
544                 ss->savedintregs[i] = *--basesp;
545         }
546
547         /* read unused callee saved flt regs */
548         
549         count = FLT_SAV_CNT;
550         for (i=0; count > code->savedfltcount; ++i) {
551                 assert(i < FLT_REG_CNT);
552                 if (nregdescfloat[i] == REG_SAV)
553                         ss->savedfltregs[--count] = es->fltregs[i];
554         }
555
556         /* read saved flt regs */
557
558         for (i=0; i<code->savedfltcount; ++i) {
559 #ifdef HAS_4BYTE_STACKSLOT
560                 basesp -= 2;
561 #else
562                 basesp--;
563 #endif
564                 ss->savedfltregs[i] = *(u8*)basesp;
565         }
566
567         /* read slots used for synchronization */
568
569         count = code_get_sync_slot_count(code);
570         ss->syncslotcount = count;
571         ss->syncslots = DMNEW(u8,count);
572         for (i=0; i<count; ++i) {
573                 ss->syncslots[i] = sp[code->memuse + i];
574         }
575 }
576
577 /* replace_write_executionstate ************************************************
578
579    Translate the given source state into an execution state.
580    
581    IN:
582        rp...............replacement point for which execution state should be
583                             creates
584            es...............where to put the execution state
585            ss...............the given source state
586
587    OUT:
588        *es..............the execution state derived from the source state
589   
590 *******************************************************************************/
591
592 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
593                                                                                  sourcestate *ss)
594 {
595         methodinfo *m;
596         codeinfo *code;
597         int count;
598         int i;
599         int t;
600         int allocs;
601         rplalloc *ra;
602         methoddesc *md;
603         int topslot;
604 #ifdef HAS_4BYTE_STACKSLOT
605         u4 *sp;
606         u4 *basesp;
607 #else
608         u8 *sp;
609         u8 *basesp;
610 #endif
611
612         code = rp->code;
613         m = code->m;
614         md = m->parseddesc;
615         topslot = TOP_IS_NORMAL;
616         
617         /* calculate stack pointer */
618         
619 #ifdef HAS_4BYTE_STACKSLOT
620         basesp = (u4*) ss->stackbase;
621 #else
622         basesp = (u8*) ss->stackbase;
623 #endif
624         
625         sp = basesp - code_get_stack_frame_size(code);
626
627         /* on some architectures the returnAddress is passed on the stack by JSR */
628
629 #if defined(__I386__) || defined(__X86_64__)
630         if (rp->type == BBTYPE_SBR) {
631                 topslot = TOP_IS_ON_STACK;
632         }
633 #endif
634         
635         /* in some cases the top stack slot is passed in REG_ITMP1 */
636
637         if (  (rp->type == BBTYPE_EXH)
638 #if defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)
639            || (rp->type == BBTYPE_SBR) 
640 #endif
641            )
642         {
643                 topslot = TOP_IS_IN_ITMP1;
644         }
645
646         /* in debug mode, invalidate stack frame first */
647
648 #ifndef NDEBUG
649         for (i=0; i<(basesp - sp); ++i) {
650                 sp[i] = 0xdeaddeadU;
651         }
652 #endif
653
654         /* write local variables */
655
656         count = m->maxlocals;
657
658         ra = code->regalloc;
659
660         i = -1;
661         for (allocs = code->globalcount; allocs--; ra++) {
662                 if (ra->next)
663                         i++;
664
665                 assert(i >= 0 && i < m->maxlocals);
666                 
667                 t = ra->type;
668                 if (t == -1)
669                         continue; /* dummy rplalloc */
670
671                 replace_write_value(es,sp,ra,ss->javalocals + (5*i+t));
672         }
673
674         /* write stack slots */
675
676         count = rp->regalloccount;
677
678         i = 0;
679         ra = rp->regalloc;
680
681         /* the first stack slot is special in SBR and EXH blocks */
682
683         if (topslot == TOP_IS_ON_STACK) {
684                 assert(count);
685                 
686                 sp[-1] = ss->javastack[i];
687                 count--;
688                 i++;
689                 ra++;
690         }
691         else if (topslot == TOP_IS_IN_ITMP1) {
692                 assert(count);
693
694                 es->intregs[REG_ITMP1] = ss->javastack[i];
695                 count--;
696                 i++;
697                 ra++;
698         }
699
700         /* write remaining stack slots */
701         
702         for (; count--; ra++, i++) {
703                 assert(ra->next);
704
705                 replace_write_value(es,sp,ra,ss->javastack + i);
706         }
707         
708         /* write unused callee saved int regs */
709         
710         count = INT_SAV_CNT;
711         for (i=0; count > code->savedintcount; ++i) {
712                 assert(i < INT_REG_CNT);
713                 if (nregdescint[i] == REG_SAV)
714                         es->intregs[i] = ss->savedintregs[--count];
715         }
716
717         /* write saved int regs */
718
719         for (i=0; i<code->savedintcount; ++i) {
720                 *--basesp = ss->savedintregs[i];
721         }
722
723         /* write unused callee saved flt regs */
724         
725         count = FLT_SAV_CNT;
726         for (i=0; count > code->savedfltcount; ++i) {
727                 assert(i < FLT_REG_CNT);
728                 if (nregdescfloat[i] == REG_SAV)
729                         es->fltregs[i] = ss->savedfltregs[--count];
730         }
731
732         /* write saved flt regs */
733
734         for (i=0; i<code->savedfltcount; ++i) {
735 #ifdef HAS_4BYTE_STACKSLOT
736                 basesp -= 2;
737 #else
738                 basesp--;
739 #endif
740                 *(u8*)basesp = ss->savedfltregs[i];
741         }
742
743         /* write slots used for synchronization */
744
745         count = code_get_sync_slot_count(code);
746         assert(count == ss->syncslotcount);
747         for (i=0; i<count; ++i) {
748                 sp[code->memuse + i] = ss->syncslots[i];
749         }
750
751         /* set new pc */
752
753         es->pc = rp->pc;
754 }
755
756 /* replace_me ******************************************************************
757  
758    This function is called by asm_replacement_out when a thread reaches
759    a replacement point. `replace_me` must map the execution state to the
760    target replacement point and let execution continue there.
761
762    This function never returns!
763   
764    IN:
765        rp...............replacement point that has been reached
766            es...............execution state read by asm_replacement_out
767   
768 *******************************************************************************/
769
770 void replace_me(rplpoint *rp,executionstate *es)
771 {
772         rplpoint *target;
773         sourcestate ss;
774         s4 dumpsize;
775         
776         /* mark start of dump memory area */
777
778         dumpsize = dump_size();
779
780         /* fetch the target of the replacement */
781
782         target = rp->target;
783
784         /* XXX DEBUG turn of self-replacement */
785         if (target == rp)
786                 replace_deactivate_replacement_point(rp);
787         
788 #ifndef NDEBUG
789         printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
790         fflush(stdout);
791         replace_replacement_point_println(rp);
792         replace_executionstate_println(es,rp->code);
793 #endif
794
795         /* read execution state of old code */
796
797         replace_read_executionstate(rp,es,&ss);
798
799 #ifndef NDEBUG
800         replace_sourcestate_println(&ss);
801 #endif
802
803         /* write execution state of new code */
804
805         replace_write_executionstate(target,es,&ss);
806
807 #ifndef NDEBUG
808         replace_executionstate_println(es,target->code);
809 #endif
810         
811         /* release dump area */
812
813         dump_release(dumpsize);
814
815         /* enter new code */
816
817 #if (defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__) || defined(__POWERPC__) || defined(__MIPS__)) && defined(ENABLE_JIT)
818         asm_replacement_in(es);
819 #endif
820         abort();
821 }
822
823 /* replace_replacement_point_println *******************************************
824  
825    Print replacement point info.
826   
827    IN:
828        rp...............the replacement point to print
829   
830 *******************************************************************************/
831
832 #ifndef NDEBUG
833 static const char *type_char = "IJFDA";
834
835 #define TYPECHAR(t)  (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
836
837 void replace_replacement_point_println(rplpoint *rp)
838 {
839         int j;
840
841         if (!rp) {
842                 printf("(rplpoint *)NULL\n");
843                 return;
844         }
845
846         printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
847                         (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
848                         (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
849
850         for (j=0; j<rp->regalloccount; ++j)
851                 printf("%c%1c%01x:%02d",
852                                 (rp->regalloc[j].next) ? '^' : ' ',
853                                 TYPECHAR(rp->regalloc[j].type),
854                                 rp->regalloc[j].flags,
855                                 rp->regalloc[j].index);
856
857         printf("]\n          method: ");
858         method_print(rp->code->m);
859
860         printf("\n");
861 }
862 #endif
863
864 /* replace_show_replacement_points *********************************************
865  
866    Print replacement point info.
867   
868    IN:
869        code.............codeinfo whose replacement points should be printed.
870   
871 *******************************************************************************/
872
873 #ifndef NDEBUG
874 void replace_show_replacement_points(codeinfo *code)
875 {
876         int i;
877         rplpoint *rp;
878         
879         if (!code) {
880                 printf("(codeinfo *)NULL\n");
881                 return;
882         }
883
884         printf("\treplacement points: %d\n",code->rplpointcount);
885         printf("\tglobal allocations: %d = [",code->globalcount);
886
887         for (i=0; i<code->globalcount; ++i)
888                 printf("%c%1c%01x:%02d",
889                                 (code->regalloc[i].next) ? '^' : ' ',
890                                 TYPECHAR(code->regalloc[i].type),
891                                 code->regalloc[i].flags,code->regalloc[i].index);
892
893         printf("]\n");
894
895         printf("\ttotal allocations : %d\n",code->regalloccount);
896         printf("\tsaved int regs    : %d\n",code->savedintcount);
897         printf("\tsaved flt regs    : %d\n",code->savedfltcount);
898         printf("\tmemuse            : %d\n",code->memuse);
899
900         printf("\n");
901
902         for (i=0; i<code->rplpointcount; ++i) {
903                 rp = code->rplpoints + i;
904
905                 assert(rp->code == code);
906                 
907                 printf("\t");
908                 replace_replacement_point_println(rp);
909         }
910 }
911 #endif
912
913 /* replace_executionstate_println **********************************************
914  
915    Print execution state
916   
917    IN:
918        es...............the execution state to print
919            code.............the codeinfo for which this execution state is meant
920                             (may be NULL)
921   
922 *******************************************************************************/
923
924 #ifndef NDEBUG
925 void replace_executionstate_println(executionstate *es,codeinfo *code)
926 {
927         int i;
928         int slots;
929 #ifdef HAS_4BYTE_STACKSLOT
930         u4 *sp;
931 #else
932         u8 *sp;
933 #endif
934
935         if (!es) {
936                 printf("(executionstate *)NULL\n");
937                 return;
938         }
939
940         printf("executionstate %p:\n",(void*)es);
941         printf("\tpc = %p\n",(void*)es->pc);
942         printf("\tsp = %p\n",(void*)es->sp);
943         printf("\tpv = %p\n",(void*)es->pv);
944         for (i=0; i<INT_REG_CNT; ++i) {
945                 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
946         }
947         for (i=0; i<FLT_REG_CNT; ++i) {
948                 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
949         }
950
951 #ifdef HAS_4BYTE_STACKSLOT
952         sp = (u4*) es->sp;
953 #else
954         sp = (u8*) es->sp;
955 #endif
956
957         if (code)
958                 slots = code_get_stack_frame_size(code);
959         else
960                 slots = 0;
961
962         printf("\tstack slots at sp:\n");
963         for (i=0; i<slots; ++i) {
964 #ifdef HAS_4BYTE_STACKSLOT
965                 printf("\t\t%08lx\n",(unsigned long)*sp++);
966 #else
967                 printf("\t\t%016llx\n",(unsigned long long)*sp++);
968 #endif
969         }
970
971         printf("\n");
972 }
973 #endif
974
975 /* replace_sourcestate_println *************************************************
976  
977    Print source state
978   
979    IN:
980        ss...............the source state to print
981   
982 *******************************************************************************/
983
984 #ifndef NDEBUG
985 void replace_sourcestate_println(sourcestate *ss)
986 {
987         int i;
988         int t;
989         int reg;
990
991         if (!ss) {
992                 printf("(sourcestate *)NULL\n");
993                 return;
994         }
995
996         printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
997
998         printf("\tlocals (%d):\n",ss->javalocalcount);
999         for (i=0; i<ss->javalocalcount; ++i) {
1000                 for (t=0; t<5; ++t) {
1001                         if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
1002                                 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
1003                                 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
1004                         }
1005                 }
1006         }
1007
1008         printf("\n");
1009
1010         printf("\tstack (depth %d):\n",ss->javastackdepth);
1011         for (i=0; i<ss->javastackdepth; ++i) {
1012                 printf("\tstack[%2d] = ",i);
1013                 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
1014         }
1015
1016         printf("\n");
1017
1018         printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1019         reg = INT_REG_CNT;
1020         for (i=0; i<INT_SAV_CNT; ++i) {
1021                 while (nregdescint[--reg] != REG_SAV)
1022                         ;
1023                 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1024                         printf("\t%-3s = ",regs[reg]);
1025                         printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1026                 }
1027         }
1028
1029         printf("\n");
1030
1031         printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1032         for (i=0; i<FLT_SAV_CNT; ++i) {
1033                 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1034                         printf("\tsavedfltreg[%2d] = ",i);
1035                         printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1036                 }
1037         }
1038         
1039         printf("\n");
1040
1041         printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1042         for (i=0; i<ss->syncslotcount; ++i) {
1043                 printf("\tslot[%2d] = ",i);
1044 #ifdef HAS_4BYTE_STACKSLOT
1045                 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1046 #else
1047                 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1048 #endif
1049         }
1050         
1051         printf("\n");
1052 }
1053 #endif
1054
1055 /*
1056  * These are local overrides for various environment variables in Emacs.
1057  * Please do not remove this and leave it at the end of the file, where
1058  * Emacs will automagically detect them.
1059  * ---------------------------------------------------------------------
1060  * Local variables:
1061  * mode: c
1062  * indent-tabs-mode: t
1063  * c-basic-offset: 4
1064  * tab-width: 4
1065  * End:
1066  * vim:noexpandtab:sw=4:ts=4:
1067  */