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